From d678ac28ea904fc6784ef5de9dd8a12679ea0ed2 Mon Sep 17 00:00:00 2001 From: Matt Thalman Date: Tue, 7 Oct 2025 07:55:24 -0500 Subject: [PATCH 01/28] Migrate VMR pipeline and orchestration fixes from 10.0.2xx (#2749) --- eng/VmrLayout.props | 2 + eng/download-source-built-archive.sh | 57 ++++++++++++++++------ eng/pipelines/official.yml | 3 ++ eng/pipelines/pr.yml | 35 +++++++++++-- eng/pipelines/scout-build.yml | 3 ++ eng/pipelines/templates/jobs/vmr-build.yml | 15 ++++-- repo-projects/Directory.Build.targets | 7 +++ test/tests.proj | 2 +- 8 files changed, 99 insertions(+), 25 deletions(-) diff --git a/eng/VmrLayout.props b/eng/VmrLayout.props index 952c0407f2c..2db8b35c83b 100644 --- a/eng/VmrLayout.props +++ b/eng/VmrLayout.props @@ -38,6 +38,8 @@ $(PreviouslySourceBuiltPackagesPath)PackageVersions.props $([MSBuild]::NormalizeDirectory('$(PrereqsPackagesDir)', 'shared-components')) $([MSBuild]::EnsureTrailingSlash('$(CustomSharedComponentsArtifactsPath)')) + $(SharedComponentsArtifactsPath)VerticalManifest.xml + $([MSBuild]::NormalizeDirectory('$(PrereqsPackagesDir)', 'extra-test-dependencies')) $([MSBuild]::NormalizeDirectory('$(SrcDir)', 'source-build-reference-packages', 'src')) $([MSBuild]::NormalizeDirectory('$(PrereqsPackagesDir)', 'reference')) diff --git a/eng/download-source-built-archive.sh b/eng/download-source-built-archive.sh index 1d4a13e1901..c56ec8753ff 100755 --- a/eng/download-source-built-archive.sh +++ b/eng/download-source-built-archive.sh @@ -5,8 +5,8 @@ # Get the repository root directory REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -# Define the path to Versions.props once PACKAGE_VERSIONS_PATH="$REPO_ROOT/eng/Versions.props" +PACKAGE_VERSION_DETAILS_PATH="$REPO_ROOT/eng/Version.Details.props" # Helper to extract a property value from an XML file function GetXmlPropertyValue { @@ -53,12 +53,20 @@ function DownloadArchive { local isRequired="$3" local artifactsRid="$4" local outputDir="$5" - local destinationFilenamePrefix="${6:-}" + local destinationFileNamePrefix="${6:-}" + local archiveBaseFileNameOverride="${7:-}" local notFoundMessage="No $label found to download..." + local sdkVersionProperty="MicrosoftNETSdkPackageVersion" local archiveVersion - archiveVersion=$(GetXmlPropertyValue "$propertyName" "$PACKAGE_VERSIONS_PATH") + local versionsPath + if [[ "$propertyName" == "$sdkVersionProperty" ]]; then + versionsPath="$PACKAGE_VERSION_DETAILS_PATH" + else + versionsPath="$PACKAGE_VERSIONS_PATH" + fi + archiveVersion=$(GetXmlPropertyValue "$propertyName" "$versionsPath") if [[ -z "$archiveVersion" ]]; then if [ "$isRequired" == true ]; then echo " ERROR: $notFoundMessage" @@ -72,16 +80,31 @@ function DownloadArchive { local archiveUrl local artifactsBaseFileName="Private.SourceBuilt.Artifacts" local prebuiltsBaseFileName="Private.SourceBuilt.Prebuilts" + local sdkBaseFileName="dotnet-sdk-" local defaultArtifactsRid='centos.10-x64' - if [[ "$propertyName" == "MicrosoftNETSdkVersion" ]]; then - archiveUrl="https://ci.dot.net/public/source-build/$artifactsBaseFileName.$archiveVersion.$artifactsRid.tar.gz" - elif [[ "$propertyName" == *Prebuilts* ]]; then - archiveUrl="https://builds.dotnet.microsoft.com/source-built-artifacts/assets/$prebuiltsBaseFileName.$archiveVersion.$defaultArtifactsRid.tar.gz" - elif [[ "$propertyName" == *Artifacts* ]]; then - archiveUrl="https://builds.dotnet.microsoft.com/source-built-artifacts/assets/$artifactsBaseFileName.$archiveVersion.$artifactsRid.tar.gz" - elif [[ "$propertyName" == *Sdk* ]]; then - archiveUrl="https://builds.dotnet.microsoft.com/source-built-artifacts/sdks/dotnet-sdk-$archiveVersion-$artifactsRid.tar.gz" + # Use override base filename if provided + if [[ -n "$archiveBaseFileNameOverride" ]]; then + artifactsBaseFileName="$archiveBaseFileNameOverride" + prebuiltsBaseFileName="$archiveBaseFileNameOverride" + sdkBaseFileName="$archiveBaseFileNameOverride" + fi + + local versionDelimiter="." + if [[ "$propertyName" == "PrivateSourceBuiltSdkVersion" ]] || [[ "$archiveBaseFileNameOverride" == *sdk* ]]; then + versionDelimiter="-" + fi + + archiveVersion="${versionDelimiter}${archiveVersion}${versionDelimiter}" + + if [[ "$propertyName" == "$sdkVersionProperty" ]]; then + archiveUrl="https://ci.dot.net/public/source-build/${artifactsBaseFileName}${archiveVersion}${artifactsRid}.tar.gz" + elif [[ "$propertyName" == "PrivateSourceBuiltPrebuiltsVersion" ]]; then + archiveUrl="https://builds.dotnet.microsoft.com/source-built-artifacts/assets/${prebuiltsBaseFileName}${archiveVersion}${defaultArtifactsRid}.tar.gz" + elif [[ "$propertyName" == "PrivateSourceBuiltArtifactsVersion" ]]; then + archiveUrl="https://builds.dotnet.microsoft.com/source-built-artifacts/assets/${artifactsBaseFileName}${archiveVersion}${artifactsRid}.tar.gz" + elif [[ "$propertyName" == "PrivateSourceBuiltSdkVersion" ]]; then + archiveUrl="https://builds.dotnet.microsoft.com/source-built-artifacts/sdks/${sdkBaseFileName}${archiveVersion}${artifactsRid}.tar.gz" else echo " ERROR: Unknown archive property name: $propertyName" return 1 @@ -94,12 +117,16 @@ function DownloadArchive { fi # Rename the file if a destination filename prefix is provided - if [[ -n "$destinationFilenamePrefix" ]]; then + if [[ -n "$destinationFileNamePrefix" ]]; then local downloadedFilename downloadedFilename=$(basename "$archiveUrl") - # Extract the suffix from the downloaded filename - local suffix="${downloadedFilename#$artifactsBaseFileName}" - local newFilename="$destinationFilenamePrefix$suffix" + # Extract the suffix from the downloaded filename using the appropriate base filename + local baseFilenameForSuffix="$artifactsBaseFileName" + if [[ "$propertyName" == *Prebuilts* ]]; then + baseFilenameForSuffix="$prebuiltsBaseFileName" + fi + local suffix="${downloadedFilename#$baseFilenameForSuffix}" + local newFilename="$destinationFileNamePrefix$suffix" mv "$outputDir/$downloadedFilename" "$outputDir/$newFilename" echo " Renamed $downloadedFilename to $newFilename" fi diff --git a/eng/pipelines/official.yml b/eng/pipelines/official.yml index 0a69a90fe04..d00866d30c6 100644 --- a/eng/pipelines/official.yml +++ b/eng/pipelines/official.yml @@ -169,3 +169,6 @@ extends: desiredFinalVersionKind: ${{ parameters.desiredFinalVersionKind }} isOfficialBuild: true scope: full + # Exclude runtime dependent jobs for any branch not producing a 1xx version since runtime-related repos aren't built in that context + # This is enabled for all branches except main and 1xx + excludeRuntimeDependentJobs: false diff --git a/eng/pipelines/pr.yml b/eng/pipelines/pr.yml index 407821d5569..150c23b9960 100644 --- a/eng/pipelines/pr.yml +++ b/eng/pipelines/pr.yml @@ -21,6 +21,25 @@ schedules: - main always: false # run only if there were changes since the last successful scheduled run. +parameters: +- name: buildScope + displayName: 'Build Scope' + type: string + default: 'auto' + values: + - auto + - lite + - full + +- name: featureBand + displayName: 'Target Feature Band' + type: string + default: 'Detect by Branch Name' + values: + - 'Detect by Branch Name' + - '1xx' + - '>= 2xx' + variables: - name: isScheduleTrigger value: ${{ eq(variables['Build.Reason'], 'Schedule') }} @@ -40,9 +59,15 @@ variables: stages: - template: /eng/pipelines/templates/stages/vmr-build.yml parameters: - ${{ if or(eq(variables.isScheduleTrigger, 'true'), contains(variables['Build.DefinitionName'], '-full')) }}: - scope: full - ${{ elseif eq(variables.isPRTrigger, 'true') }}: - scope: lite + ${{ if eq(parameters.buildScope, 'auto') }}: + ${{ if or(eq(variables.isScheduleTrigger, 'true'), contains(variables['Build.DefinitionName'], '-full')) }}: + scope: full + ${{ elseif eq(variables.isPRTrigger, 'true') }}: + scope: lite + ${{ else }}: + scope: full ${{ else }}: - scope: full + scope: ${{ parameters.buildScope }} + # Exclude runtime dependent jobs for any branch not producing a 1xx version since runtime-related repos aren't built in that context + # This is enabled for all branches except main and 1xx + excludeRuntimeDependentJobs: false diff --git a/eng/pipelines/scout-build.yml b/eng/pipelines/scout-build.yml index c4e8ea5bb2f..0cb923a5b9d 100644 --- a/eng/pipelines/scout-build.yml +++ b/eng/pipelines/scout-build.yml @@ -32,3 +32,6 @@ stages: - template: /eng/pipelines/templates/stages/vmr-build.yml parameters: scope: scout + # Exclude runtime dependent jobs for any branch not producing a 1xx version since runtime-related repos aren't built in that context + # This is enabled for all branches except main and 1xx + excludeRuntimeDependentJobs: false diff --git a/eng/pipelines/templates/jobs/vmr-build.yml b/eng/pipelines/templates/jobs/vmr-build.yml index 43a34a8a7f7..30a03a292fa 100644 --- a/eng/pipelines/templates/jobs/vmr-build.yml +++ b/eng/pipelines/templates/jobs/vmr-build.yml @@ -411,10 +411,17 @@ jobs: DownloadArchive "source-built SDK" "PrivateSourceBuiltSdkVersion" false "${{ parameters.artifactsRid }}" "$(sourcesPath)/prereqs/packages/archive/" displayName: Download Previously Source-Built SDK - - ${{ if eq(parameters.excludeRuntimeDependentJobs, 'true') }}: + - ${{ if and(parameters.excludeRuntimeDependentJobs, eq(parameters.reuseBuildArtifactsFrom, ''), not(parameters.withPreviousSDK)) }}: - script: | source "$(sourcesPath)/eng/download-source-built-archive.sh" - DownloadArchive "shared component artifacts" "MicrosoftNETSdkVersion" false "${{ parameters.artifactsRid }}" "$(sourcesPath)/prereqs/packages/archive/" "Private.SourceBuilt.SharedComponents" + # Download the 1xx source-built SDK + DownloadArchive "1xx source-built SDK" "MicrosoftNETSdkPackageVersion" false "${{ parameters.artifactsRid }}" "$(sourcesPath)/prereqs/packages/archive/" "" "dotnet-sdk" + displayName: Download 1xx SDK + + - ${{ if parameters.excludeRuntimeDependentJobs }}: + - script: | + source "$(sourcesPath)/eng/download-source-built-archive.sh" + DownloadArchive "shared component artifacts" "MicrosoftNETSdkPackageVersion" false "${{ parameters.artifactsRid }}" "$(sourcesPath)/prereqs/packages/archive/" "Private.SourceBuilt.SharedComponents" displayName: Download Shared Component Artifacts # https://github.com/dotnet/dotnet/issues/1758 @@ -504,8 +511,8 @@ jobs: customPrepArgs="" prepSdk=true - if [[ '${{ parameters.withPreviousSDK }}' == 'True' ]]; then - # Using previous SDK implies we do not want to bootstrap. + if [[ '${{ parameters.withPreviousSDK }}' == 'True' ]] || [[ '${{ parameters.excludeRuntimeDependentJobs }}' == 'True' ]]; then + # Using source-built SDK implies we do not want to bootstrap. customPrepArgs="${customPrepArgs} --no-sdk --no-bootstrap" prepSdk=false elif [[ '${{ length(parameters.reuseBuildArtifactsFrom) }}' -gt '0' ]]; then diff --git a/repo-projects/Directory.Build.targets b/repo-projects/Directory.Build.targets index 06b77c79ad3..4bbf095e231 100644 --- a/repo-projects/Directory.Build.targets +++ b/repo-projects/Directory.Build.targets @@ -174,6 +174,7 @@ previously-source-built shared-components reference-packages + extra-test-dependencies true false @@ -182,6 +183,7 @@ <_CommonBuildSources Include="@(DependentRepoSourceName)" /> <_CommonBuildSources Include="$(ExtraSourcesNuGetSourceName)" Condition="'$(ExtraRestoreSourcePath)' != ''" /> + <_CommonBuildSources Include="$(ExtraTestDependenciesNuGetSourceName)" Condition="Exists('$(ExtraTestDependenciesRestoreSourcePath)')" /> @@ -241,6 +243,11 @@ SourcePath="$(ExtraRestoreSourcePath)" Condition="'$(ExtraRestoreSourcePath)' != ''" /> + + From e15b1c0a8c7f47abd64339c6bfb5bde268b3f5db Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 20:07:05 -0700 Subject: [PATCH 02/28] [release/10.0.1xx] Source code updates from dotnet/sdk (#2771) Co-authored-by: dotnet-maestro[bot] Co-authored-by: AR-May <67507805+AR-May@users.noreply.github.com> Co-authored-by: Premek Vysoky Co-authored-by: Matt Mitchell (.NET) --- src/sdk/.github/copilot-instructions.md | 5 + src/sdk/.vsts-ci.yml | 15 + src/sdk/Directory.Packages.props | 5 +- src/sdk/build/RunTestTemplateTests.ps1 | 46 -- .../general/analyzer-redirecting.md | 36 +- .../documentation/general/dotnet-run-file.md | 6 +- .../documentation/manpages/sdk/dotnet-build.1 | 54 +- .../documentation/manpages/sdk/dotnet-clean.1 | 37 +- .../documentation/manpages/sdk/dotnet-pack.1 | 6 +- .../manpages/sdk/dotnet-publish.1 | 47 +- .../manpages/sdk/dotnet-restore.1 | 28 +- .../documentation/manpages/sdk/dotnet-run.1 | 79 ++- .../documentation/manpages/sdk/dotnet-watch.1 | 4 +- .../documentation/project-docs/telemetry.md | 90 ++- src/sdk/eng/Version.Details.props | 264 ++++----- src/sdk/eng/Version.Details.xml | 530 +++++++++--------- src/sdk/eng/common/SetupNugetSources.ps1 | 2 +- src/sdk/eng/common/SetupNugetSources.sh | 2 +- .../job/publish-build-assets.yml | 7 - .../core-templates/job/source-build.yml | 4 - .../eng/common/core-templates/jobs/jobs.yml | 2 - .../core-templates/jobs/source-build.yml | 5 - .../core-templates/steps/source-build.yml | 4 - .../dotnet-format-integration.yml | 18 +- .../pipelines/templates/jobs/sdk-build.yml | 22 +- .../templates/jobs/sdk-job-matrix.yml | 1 - src/sdk/global.json | 6 +- src/sdk/sdk.slnx | 1 + ...soft.NET.Sdk.BlazorWebAssembly.6_0.targets | 61 -- .../AspireService/AspireServerService.cs | 36 +- .../Models/SessionChangeNotification.cs | 9 + .../DotNetDeltaApplier/StartupHook.cs | 2 +- .../HotReloadClient/DefaultHotReloadClient.cs | 36 +- .../HotReloadClient/HotReloadClient.cs | 21 +- .../HotReloadClient/HotReloadClients.cs | 13 +- .../HotReloadClient/Logging/LogEvents.cs | 2 + .../Web/AbstractBrowserRefreshServer.cs | 10 +- .../HotReloadClient/Web/BrowserConnection.cs | 2 +- .../Formatters/CharsetFormatter.cs | 3 +- src/sdk/src/BuiltInTools/dotnet-watch.slnf | 3 +- .../Aspire/AspireServiceFactory.cs | 38 +- .../dotnet-watch/Browser/BrowserLauncher.cs | 50 +- .../Build/ProjectGraphUtilities.cs | 4 + .../CommandLine/EnvironmentOptions.cs | 5 + .../HotReload/CompilationHandler.cs | 259 ++++----- .../HotReload/HotReloadDotNetWatcher.cs | 29 +- .../dotnet-watch/Process/ProcessRunner.cs | 120 ++-- .../dotnet-watch/Process/ProcessSpec.cs | 3 +- .../dotnet-watch/Process/ProjectLauncher.cs | 10 +- .../dotnet-watch/Process/RunningProject.cs | 59 +- .../src/BuiltInTools/dotnet-watch/Program.cs | 2 +- .../Properties/launchSettings.json | 2 +- .../dotnet-watch/UI/ConsoleReporter.cs | 8 +- .../BuiltInTools/dotnet-watch/UI/IReporter.cs | 3 + .../Microsoft.DotNet.Cli.Utils/Constants.cs | 8 + .../MSBuildForwardingAppWithoutLogging.cs | 1 - .../LocalizableStrings.Designer.cs | 11 + .../LocalizableStrings.resx | 8 +- .../AddJsonPropertyPostActionProcessor.cs | 62 +- .../xlf/LocalizableStrings.cs.xlf | 9 + .../xlf/LocalizableStrings.de.xlf | 9 + .../xlf/LocalizableStrings.es.xlf | 9 + .../xlf/LocalizableStrings.fr.xlf | 9 + .../xlf/LocalizableStrings.it.xlf | 9 + .../xlf/LocalizableStrings.ja.xlf | 9 + .../xlf/LocalizableStrings.ko.xlf | 9 + .../xlf/LocalizableStrings.pl.xlf | 9 + .../xlf/LocalizableStrings.pt-BR.xlf | 9 + .../xlf/LocalizableStrings.ru.xlf | 9 + .../xlf/LocalizableStrings.tr.xlf | 9 + .../xlf/LocalizableStrings.zh-Hans.xlf | 9 + .../xlf/LocalizableStrings.zh-Hant.xlf | 9 + src/sdk/src/Cli/dotnet/CliStrings.resx | 5 +- .../dotnet/Commands/CliCommandStrings.resx | 36 +- .../Commands/MSBuild/MSBuildForwardingApp.cs | 7 +- .../dotnet/Commands/MSBuild/MSBuildLogger.cs | 119 ++-- .../Commands/Package/Add/PackageAddCommand.cs | 16 +- .../Project/Convert/ProjectConvertCommand.cs | 40 +- .../Run/CSharpCompilerCommand.Generated.cs | 1 - .../dotnet/Commands/Run/CommonRunHelpers.cs | 26 +- .../Commands/Run/FileBasedAppSourceEditor.cs | 18 +- .../src/Cli/dotnet/Commands/Run/RunCommand.cs | 24 +- .../Cli/dotnet/Commands/Run/RunTelemetry.cs | 16 +- .../Run/VirtualProjectBuildingCommand.cs | 103 ++-- .../HumanReadableDurationFormatter.cs | 1 + .../Test/MTP/Terminal/TerminalTestReporter.cs | 14 +- .../Commands/Test/MTP/TestApplication.cs | 113 ++-- .../dotnet/Commands/Test/TestCommandParser.cs | 5 +- .../Commands/Test/VSTest/TestCommand.cs | 12 +- .../Tool/Install/ToolInstallCommandParser.cs | 2 +- .../ToolInstallGlobalOrToolPathCommand.cs | 17 +- .../Tool/Update/ToolUpdateCommandParser.cs | 2 +- .../Commands/xlf/CliCommandStrings.cs.xlf | 114 ++-- .../Commands/xlf/CliCommandStrings.de.xlf | 114 ++-- .../Commands/xlf/CliCommandStrings.es.xlf | 114 ++-- .../Commands/xlf/CliCommandStrings.fr.xlf | 114 ++-- .../Commands/xlf/CliCommandStrings.it.xlf | 114 ++-- .../Commands/xlf/CliCommandStrings.ja.xlf | 114 ++-- .../Commands/xlf/CliCommandStrings.ko.xlf | 114 ++-- .../Commands/xlf/CliCommandStrings.pl.xlf | 114 ++-- .../Commands/xlf/CliCommandStrings.pt-BR.xlf | 114 ++-- .../Commands/xlf/CliCommandStrings.ru.xlf | 114 ++-- .../Commands/xlf/CliCommandStrings.tr.xlf | 114 ++-- .../xlf/CliCommandStrings.zh-Hans.xlf | 114 ++-- .../xlf/CliCommandStrings.zh-Hant.xlf | 114 ++-- src/sdk/src/Cli/dotnet/CommonArguments.cs | 10 +- .../NuGetPackageDownloader.cs | 14 + src/sdk/src/Cli/dotnet/Program.cs | 10 +- .../Telemetry/EnvironmentDetectionRule.cs | 16 +- .../Telemetry/ILLMEnvironmentDetector.cs | 10 +- .../LLMEnvironmentDetectorForTelemetry.cs | 19 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.cs.xlf | 37 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.de.xlf | 35 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.es.xlf | 27 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.fr.xlf | 31 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.it.xlf | 35 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.ja.xlf | 27 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.ko.xlf | 27 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.pl.xlf | 43 +- .../src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf | 35 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.ru.xlf | 35 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.tr.xlf | 43 +- .../src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf | 27 +- .../src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf | 27 +- ....Common.Net.Core.SDK.RuntimeAnalyzers.proj | 39 +- .../windows/bundles/sdk/LCID/1028/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/1029/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/1031/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/1036/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/1040/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/1041/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/1042/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/1045/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/1046/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/1049/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/1055/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/2052/bundle.wxl | 4 +- .../windows/bundles/sdk/LCID/3082/bundle.wxl | 4 +- src/sdk/src/Layout/redist/redist.csproj | 2 +- .../CSharpDetectPreviewFeatureAnalyzer.cs | 14 + .../Runtime/DetectPreviewFeatureAnalyzer.cs | 8 +- .../BasicDetectPreviewFeatureAnalyzer.vb | 7 +- .../Analyzer.CSharp.Utilities.projitems | 3 +- .../Lightup/AwaitExpressionInfoWrapper.cs | 33 ++ .../Compiler/Lightup/LightupHelpers.cs | 2 +- .../DetectPreviewFeatureUnitTests.Misc.cs | 131 ++++- ...crosoft.Net.Sdk.AnalyzerRedirecting.csproj | 1 + .../SdkAnalyzerAssemblyRedirector.cs | 107 +++- .../source.extension.vsixmanifest | 6 +- .../MSBuildSdkResolver.cs | 6 +- .../Microsoft.DotNet.NativeWrapper/Interop.cs | 8 +- .../NETCoreSdkResolverNativeWrapper.cs | 20 + .../Tasks/Data/StaticWebAssetPathPattern.cs | 67 +++ .../Tasks/DefineStaticWebAssets.cs | 35 +- ...GenerateStaticWebAssetEndpointsManifest.cs | 44 ++ .../Tasks/Common/Resources/xlf/Strings.cs.xlf | 8 +- .../Tasks/Common/Resources/xlf/Strings.de.xlf | 8 +- .../Tasks/Common/Resources/xlf/Strings.es.xlf | 8 +- .../Tasks/Common/Resources/xlf/Strings.fr.xlf | 8 +- .../Tasks/Common/Resources/xlf/Strings.it.xlf | 8 +- .../Tasks/Common/Resources/xlf/Strings.ja.xlf | 8 +- .../Tasks/Common/Resources/xlf/Strings.ko.xlf | 8 +- .../Tasks/Common/Resources/xlf/Strings.pl.xlf | 8 +- .../Common/Resources/xlf/Strings.pt-BR.xlf | 8 +- .../Tasks/Common/Resources/xlf/Strings.ru.xlf | 8 +- .../Tasks/Common/Resources/xlf/Strings.tr.xlf | 8 +- .../Common/Resources/xlf/Strings.zh-Hans.xlf | 8 +- .../Common/Resources/xlf/Strings.zh-Hant.xlf | 8 +- .../targets/Microsoft.NET.PackTool.targets | 7 +- ...osoft.NET.TargetFrameworkInference.targets | 6 +- .../sdk-tasks/GenerateRuntimeAnalyzersSWR.cs | 24 +- .../ProcessRuntimeAnalyzerVersions.cs | 58 ++ .../Tasks/sdk-tasks/sdk-tasks.InTree.targets | 1 + .../localize/templatestrings.cs.json | 8 +- .../localize/templatestrings.de.json | 8 +- .../localize/templatestrings.es.json | 8 +- .../localize/templatestrings.fr.json | 8 +- .../localize/templatestrings.it.json | 8 +- .../localize/templatestrings.ja.json | 8 +- .../localize/templatestrings.ko.json | 8 +- .../localize/templatestrings.pl.json | 8 +- .../localize/templatestrings.pt-BR.json | 8 +- .../localize/templatestrings.ru.json | 8 +- .../localize/templatestrings.tr.json | 8 +- .../localize/templatestrings.zh-Hans.json | 8 +- .../localize/templatestrings.zh-Hant.json | 8 +- .../localize/templatestrings.cs.json | 4 +- .../localize/templatestrings.de.json | 4 +- .../localize/templatestrings.es.json | 4 +- .../localize/templatestrings.fr.json | 4 +- .../localize/templatestrings.it.json | 4 +- .../localize/templatestrings.ja.json | 4 +- .../localize/templatestrings.ko.json | 4 +- .../localize/templatestrings.pl.json | 4 +- .../localize/templatestrings.pt-BR.json | 4 +- .../localize/templatestrings.ru.json | 4 +- .../localize/templatestrings.tr.json | 4 +- .../localize/templatestrings.zh-Hans.json | 4 +- .../localize/templatestrings.zh-Hant.json | 4 +- .../.template.config/template.json | 4 +- .../localize/templatestrings.cs.json | 4 +- .../localize/templatestrings.de.json | 4 +- .../localize/templatestrings.es.json | 4 +- .../localize/templatestrings.fr.json | 4 +- .../localize/templatestrings.it.json | 4 +- .../localize/templatestrings.ja.json | 4 +- .../localize/templatestrings.ko.json | 4 +- .../localize/templatestrings.pl.json | 4 +- .../localize/templatestrings.pt-BR.json | 4 +- .../localize/templatestrings.ru.json | 4 +- .../localize/templatestrings.tr.json | 4 +- .../localize/templatestrings.zh-Hans.json | 4 +- .../localize/templatestrings.zh-Hant.json | 4 +- .../.template.config/template.json | 4 +- .../localize/templatestrings.cs.json | 4 +- .../localize/templatestrings.de.json | 4 +- .../localize/templatestrings.es.json | 4 +- .../localize/templatestrings.fr.json | 4 +- .../localize/templatestrings.it.json | 4 +- .../localize/templatestrings.ja.json | 4 +- .../localize/templatestrings.ko.json | 4 +- .../localize/templatestrings.pl.json | 4 +- .../localize/templatestrings.pt-BR.json | 4 +- .../localize/templatestrings.ru.json | 4 +- .../localize/templatestrings.tr.json | 4 +- .../localize/templatestrings.zh-Hans.json | 4 +- .../localize/templatestrings.zh-Hant.json | 4 +- .../.template.config/template.json | 4 +- .../localize/templatestrings.cs.json | 4 +- .../localize/templatestrings.de.json | 4 +- .../localize/templatestrings.es.json | 4 +- .../localize/templatestrings.fr.json | 4 +- .../localize/templatestrings.it.json | 4 +- .../localize/templatestrings.ja.json | 4 +- .../localize/templatestrings.ko.json | 4 +- .../localize/templatestrings.pl.json | 4 +- .../localize/templatestrings.pt-BR.json | 4 +- .../localize/templatestrings.ru.json | 4 +- .../localize/templatestrings.tr.json | 4 +- .../localize/templatestrings.zh-Hans.json | 4 +- .../localize/templatestrings.zh-Hant.json | 4 +- .../.template.config/template.json | 4 +- .../XUnit-CSharp/Company.TestProject1.csproj | 23 +- .../content/XUnit-CSharp/xunit.runner.json | 3 - .../XUnit-FSharp/Company.TestProject1.fsproj | 23 +- .../content/XUnit-FSharp/xunit.runner.json | 3 - .../Company.TestProject1.vbproj | 23 +- .../XUnit-VisualBasic/xunit.runner.json | 3 - ...hatWeWantToBuildANetCoreAppForTelemetry.cs | 5 +- .../RoslynBuildTaskTests.cs | 17 +- .../GivenThatWeWantToPublishAnAotApp.cs | 3 +- .../GivenThatWeWantToPublishIncrementally.cs | 2 +- .../WasmPublishIntegrationTest.cs | 10 + .../ScopedCssIntegrationTests.cs | 68 +++ .../DiscoverStaticWebAssetsTest.cs | 65 ++- .../SdkAnalyzerAssemblyRedirectorTests.cs | 18 +- ...lazorWasmReferencedByAspNetCoreServer.slnx | 4 + .../Client/App.razor | 6 + .../Client/Client.csproj | 16 + .../Client/Program.cs | 11 + .../Client/_Imports.razor | 9 + .../Client/wwwroot/css/app.css | 2 + .../Client/wwwroot/index.html | 33 ++ .../Client/wwwroot/manifest.webmanifest | 8 + .../Client/wwwroot/service-worker.js | 2 + .../wwwroot/service-worker.published.js | 3 + .../Server/Program.cs | 16 + .../Server/Server.csproj | 14 + .../WatchAspire.ApiService/Program.cs | 2 +- .../WatchAspire.AppHost/Program.cs | 7 +- .../WatchAspire.AppHost.csproj | 7 +- .../WatchAspire.MigrationService/Program.cs | 10 + .../Properties/launchSettings.json | 12 + .../WatchAspire.MigrationService.csproj | 11 + .../WatchAspire.MigrationService/Worker.cs | 22 + .../appsettings.Development.json | 8 + .../appsettings.json | 8 + .../WatchAspire/WatchAspire.Wasm/App.razor | 2 +- .../TestProjects/WatchAspire/WatchAspire.slnx | 8 + .../TestProjects/WatchHotReloadApp/Program.cs | 1 + .../RazorApp/Components/Pages/Home.razor | 9 +- .../test/dotnet-watch-test-browser/Program.cs | 146 +++++ .../dotnet-watch-test-browser.csproj | 14 + .../Browser/BrowserLaunchTests.cs | 49 -- .../Browser/BrowserRefreshServerTests.cs | 59 ++ .../Browser/BrowserTests.cs | 110 ++++ .../Build/EvaluationTests.cs | 24 +- .../CommandLine/LaunchSettingsTests.cs | 17 +- .../ConsoleReporterTests.cs | 8 +- .../HotReload/ApplyDeltaTests.cs | 110 +++- .../HotReload/CompilationHandlerTests.cs | 2 +- .../HotReload/RuntimeProcessLauncherTests.cs | 3 +- .../TestUtilities/AssertEx.cs | 35 +- .../TestUtilities/TestBrowserRefreshServer.cs | 17 + .../TestUtilities/TestLogger.cs | 4 +- .../TestUtilities/TestLoggerFactory.cs | 17 + .../TestUtilities/WatchableApp.cs | 29 +- .../Watch/BuildEvaluatorTests.cs | 6 +- .../Watch/NoRestoreTests.cs | 6 +- .../dotnet-watch.Tests.csproj | 13 + .../CommandTests/MSBuild/FakeTelemetry.cs | 4 +- .../MSBuild/GivenDotnetBuildInvocation.cs | 48 +- .../MSBuild/GivenMSBuildLogger.cs | 107 +++- .../Package/Add/GivenDotnetPackageAdd.cs | 108 +++- .../Convert/DotnetProjectConvertTests.cs | 222 +++++++- .../Run/FileBasedAppSourceEditorTests.cs | 66 +++ .../CommandTests/Run/RunFileTests.cs | 354 ++++++++++-- .../CommandTests/Run/RunTelemetryTests.cs | 38 +- ...enDotnetTestBuildsAndRunsTestfromCsproj.cs | 32 ++ ...ToolInstallGlobalOrToolPathCommandTests.cs | 75 ++- ...napshotTests.VerifyCompletions.verified.sh | 6 +- ...apshotTests.VerifyCompletions.verified.ps1 | 3 +- ...apshotTests.VerifyCompletions.verified.zsh | 9 +- .../TelemetryCommonPropertiesTests.cs | 83 +-- src/source-manifest.json | 4 +- .../DotNetWatchTests.cs | 26 +- 316 files changed, 5780 insertions(+), 2574 deletions(-) delete mode 100644 src/sdk/build/RunTestTemplateTests.ps1 create mode 100644 src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Lightup/AwaitExpressionInfoWrapper.cs create mode 100644 src/sdk/src/Tasks/sdk-tasks/ProcessRuntimeAnalyzerVersions.cs delete mode 100644 src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-CSharp/xunit.runner.json delete mode 100644 src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/xunit.runner.json delete mode 100644 src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/xunit.runner.json create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/BlazorWasmReferencedByAspNetCoreServer.slnx create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/App.razor create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/Client.csproj create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/Program.cs create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/_Imports.razor create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/css/app.css create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/index.html create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/manifest.webmanifest create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/service-worker.js create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/service-worker.published.js create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Server/Program.cs create mode 100644 src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Server/Server.csproj create mode 100644 src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Program.cs create mode 100644 src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Properties/launchSettings.json create mode 100644 src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/WatchAspire.MigrationService.csproj create mode 100644 src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Worker.cs create mode 100644 src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.Development.json create mode 100644 src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.json create mode 100644 src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.slnx create mode 100644 src/sdk/test/dotnet-watch-test-browser/Program.cs create mode 100644 src/sdk/test/dotnet-watch-test-browser/dotnet-watch-test-browser.csproj delete mode 100644 src/sdk/test/dotnet-watch.Tests/Browser/BrowserLaunchTests.cs create mode 100644 src/sdk/test/dotnet-watch.Tests/Browser/BrowserRefreshServerTests.cs create mode 100644 src/sdk/test/dotnet-watch.Tests/Browser/BrowserTests.cs create mode 100644 src/sdk/test/dotnet-watch.Tests/TestUtilities/TestBrowserRefreshServer.cs create mode 100644 src/sdk/test/dotnet-watch.Tests/TestUtilities/TestLoggerFactory.cs diff --git a/src/sdk/.github/copilot-instructions.md b/src/sdk/.github/copilot-instructions.md index 00e3e87beec..c31c8405a9b 100644 --- a/src/sdk/.github/copilot-instructions.md +++ b/src/sdk/.github/copilot-instructions.md @@ -16,6 +16,11 @@ Testing: - Examples: - `dotnet test test/dotnet.Tests/dotnet.Tests.csproj --filter "Name~ItShowsTheAppropriateMessageToTheUser"` - `dotnet exec artifacts/bin/redist/Debug/dotnet.Tests.dll -method "*ItShowsTheAppropriateMessageToTheUser*"` +- To test CLI command changes: + - Build the redist SDK: `./build.sh` from repo root + - Create a dogfood environment: `source eng/dogfood.sh` + - Test commands in the dogfood shell (e.g., `dnx --help`, `dotnet tool install --help`) + - The dogfood script sets up PATH and environment to use the newly built SDK Output Considerations: - When considering how output should look, solicit advice from baronfel. diff --git a/src/sdk/.vsts-ci.yml b/src/sdk/.vsts-ci.yml index cdee394e48f..82dded31616 100644 --- a/src/sdk/.vsts-ci.yml +++ b/src/sdk/.vsts-ci.yml @@ -102,6 +102,7 @@ extends: oneESCompat: templateFolderName: templates-official publishTaskPrefix: 1ES. + populateInternalRuntimeVariables: true runtimeSourceProperties: /p:DotNetRuntimeSourceFeed=https://ci.dot.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) locBranch: release/10.0.1xx # WORKAROUND: BinSkim requires the folder exist prior to scanning. @@ -141,6 +142,14 @@ extends: _SignType: real dependsOn: Official_windows_x64 downloadManifestMsiPackages: true + ### TestTemplatesCG ### + # Note: This job is only used to allow the test templates to be built locally on the agent as opposed to Helix. + # The tests acquire the templates' PackageReferences from NuGet, which allows them to be scanned by CG (component governance). + # CG is only ran internally, so this job makes sense to only run alongside of the official jobs. + - categoryName: TestTemplatesCG + testProjects: $(Build.SourcesDirectory)/test/dotnet-new.IntegrationTests/dotnet-new.IntegrationTests.csproj + testRunnerAdditionalArguments: -class Microsoft.DotNet.Cli.New.IntegrationTests.DotnetNewTestTemplatesTests + publishXunitResults: true ############### LINUX ############### - template: /eng/pipelines/templates/jobs/sdk-job-matrix.yml@self @@ -153,6 +162,7 @@ extends: oneESCompat: templateFolderName: templates-official publishTaskPrefix: 1ES. + populateInternalRuntimeVariables: true runtimeSourceProperties: /p:DotNetRuntimeSourceFeed=https://ci.dot.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) ${{ if and(eq(parameters.runTestBuild, false), ne(variables['Build.Reason'], 'PullRequest')) }}: timeoutInMinutes: 90 @@ -235,6 +245,7 @@ extends: oneESCompat: templateFolderName: templates-official publishTaskPrefix: 1ES. + populateInternalRuntimeVariables: true runtimeSourceProperties: /p:DotNetRuntimeSourceFeed=https://ci.dot.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) ${{ if and(eq(parameters.runTestBuild, false), ne(variables['Build.Reason'], 'PullRequest')) }}: timeoutInMinutes: 90 @@ -260,6 +271,8 @@ extends: vmImage: macOS-latest os: macOS helixTargetQueue: osx.13.arm64 + populateInternalRuntimeVariables: true + runtimeSourceProperties: /p:DotNetRuntimeSourceFeed=https://ci.dot.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) macOSJobParameterSets: - categoryName: TestBuild targetArchitecture: arm64 @@ -270,7 +283,9 @@ extends: - template: /eng/dotnet-format/dotnet-format-integration.yml@self parameters: oneESCompat: + templateFolderName: templates-official publishTaskPrefix: 1ES. + populateInternalRuntimeVariables: true runtimeSourceProperties: /p:DotNetRuntimeSourceFeed=https://ci.dot.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) ############### PUBLISH STAGE ############### diff --git a/src/sdk/Directory.Packages.props b/src/sdk/Directory.Packages.props index ca461b8d0f0..ecc47ba3f16 100644 --- a/src/sdk/Directory.Packages.props +++ b/src/sdk/Directory.Packages.props @@ -5,10 +5,11 @@ $(NoWarn);NU1507 - + + @@ -93,7 +94,7 @@ - + diff --git a/src/sdk/build/RunTestTemplateTests.ps1 b/src/sdk/build/RunTestTemplateTests.ps1 deleted file mode 100644 index 5fe903b77f3..00000000000 --- a/src/sdk/build/RunTestTemplateTests.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -<# -.SYNOPSIS - Runs Microsoft.TestTemplates.Acceptance.Tests.dll in the dogfood environment. -.DESCRIPTION - This script enters the dogfood environment and runs the RunTestTemplateTests tests. -#> -[CmdletBinding(PositionalBinding=$false)] -Param( - [string] $configuration = "Release" -) - -function Run-TestTemplateTests { - $ErrorActionPreference = 'Stop' - $RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..') - $classNameFilter = "--filter" - $filterValue = "FullyQualifiedName~Microsoft.DotNet.Cli.New.IntegrationTests.DotnetNewTestTemplatesTests" - $TestDll = Join-Path $RepoRoot "artifacts\bin\dotnet-new.IntegrationTests\$configuration\dotnet-new.IntegrationTests.dll" - - # Check if the test DLL exists - if (-not (Test-Path $TestDll)) { - Write-Error "Test DLL not found at: $TestDll" - return 1 - } - - Write-Host "Running tests for test templates in the dogfood environment..." -ForegroundColor Cyan - - # Call dogfood.ps1 directly instead of through dogfood.cmd to avoid the -NoExit parameter - $dogfoodPs1 = Join-Path $RepoRoot "eng\dogfood.ps1" - - Write-Host "Executing: dotnet test $TestDll via dogfood environment" -ForegroundColor Gray - # Pass the command directly to the dogfood.ps1 script - & $dogfoodPs1 -configuration $configuration -command @("dotnet", "test", $TestDll, $classNameFilter, $filterValue) - - $exitCode = $LASTEXITCODE - if ($exitCode -ne 0) { - Write-Error "Tests failed with exit code: $exitCode" - } else { - Write-Host "Tests completed successfully!" -ForegroundColor Green - } - - return $exitCode -} - -# Execute the function using Invoke-Command -$exitCode = Invoke-Command -ScriptBlock ${function:Run-TestTemplateTests} -exit $exitCode diff --git a/src/sdk/documentation/general/analyzer-redirecting.md b/src/sdk/documentation/general/analyzer-redirecting.md index 208c2873478..e999b98d76f 100644 --- a/src/sdk/documentation/general/analyzer-redirecting.md +++ b/src/sdk/documentation/general/analyzer-redirecting.md @@ -28,21 +28,36 @@ Targeting an SDK (and hence also loading analyzers) with newer major version in - Note that when `IAnalyzerAssemblyRedirector` is involved, Roslyn is free to not use shadow copy loading and instead load the DLLs directly. +- It is possible to opt out of analyzer redirecting by setting environment variable `DOTNET_ANALYZER_REDIRECTING=0`. + That is an unsupported scenario though and compiler version mismatch errors will likely occur. + ## Details The VSIX contains some analyzers, for example: ``` -AspNetCoreAnalyzers\9.0.0-preview.5.24306.11\analyzers\dotnet\cs\Microsoft.AspNetCore.App.Analyzers.dll -NetCoreAnalyzers\9.0.0-preview.5.24306.7\analyzers\dotnet\cs\System.Text.RegularExpressions.Generator.dll -WindowsDesktopAnalyzers\9.0.0-preview.5.24306.8\analyzers\dotnet\System.Windows.Forms.Analyzers.dll -SDKAnalyzers\9.0.100-dev\Sdks\Microsoft.NET.Sdk\analyzers\Microsoft.CodeAnalysis.NetAnalyzers.dll -WebSDKAnalyzers\9.0.100-dev\Sdks\Microsoft.NET.Sdk.Web\analyzers\cs\Microsoft.AspNetCore.Analyzers.dll +AspNetCoreAnalyzers\analyzers\dotnet\cs\Microsoft.AspNetCore.App.Analyzers.dll +NetCoreAnalyzers\analyzers\dotnet\cs\System.Text.RegularExpressions.Generator.dll +WindowsDesktopAnalyzers\analyzers\dotnet\System.Windows.Forms.Analyzers.dll +SDKAnalyzers\Sdks\Microsoft.NET.Sdk\analyzers\Microsoft.CodeAnalysis.NetAnalyzers.dll +WebSDKAnalyzers\Sdks\Microsoft.NET.Sdk.Web\analyzers\cs\Microsoft.AspNetCore.Analyzers.dll +``` + +And metadata at `metadata.json`: + +```json +{ + "AspNetCoreAnalyzers": "9.0.0-preview.5.24306.11", + "NetCoreAnalyzers": "9.0.0-preview.5.24306.7", + "WindowsDesktopAnalyzers": "9.0.0-preview.5.24306.8", + "SDKAnalyzers": "9.0.100-dev", + "WebSDKAnalyzers": "9.0.100-dev", +} ``` Given an analyzer assembly load going through our `IAnalyzerAssemblyRedirector`, we will redirect it if the original path of the assembly being loaded matches the path of a VSIX-deployed analyzer - -only segments of these paths starting after the version segment are compared, +only relevant segments (see example below) of these paths are compared, plus the major and minor component of the versions must match. For example, the analyzer @@ -54,10 +69,10 @@ C:\Program Files\dotnet\sdk\9.0.100-preview.5.24307.3\Sdks\Microsoft.NET.Sdk\ana will be redirected to ``` -{VSIX}\SDKAnalyzers\9.0.100-dev\Sdks\Microsoft.NET.Sdk\analyzers\Microsoft.CodeAnalysis.NetAnalyzers.dll +{VSIX}\SDKAnalyzers\Sdks\Microsoft.NET.Sdk\analyzers\Microsoft.CodeAnalysis.NetAnalyzers.dll ``` -because +where `metadata.json` has `"SDKAnalyzers": "9.0.100-dev"`, because 1. the suffix `Sdks\Microsoft.NET.Sdk\analyzers\Microsoft.CodeAnalysis.NetAnalyzers.dll` matches, and 2. the version `9.0.100-preview.5.24307.3` has the same major and minor component (`9.0`) as the version `9.0.100-dev` (both versions are read from the paths, not DLL metadata). @@ -65,4 +80,9 @@ because Analyzers that cannot be matched will continue to be loaded from the SDK (and will fail to load if they reference Roslyn that is newer than is in VS). +### Implementation + +Analyzer DLLs are contained in transport package `VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers`. +The redirecting logic lives in "system" VS extension `Microsoft.Net.Sdk.AnalyzerRedirecting`. + [torn-sdk]: https://github.com/dotnet/sdk/issues/42087 diff --git a/src/sdk/documentation/general/dotnet-run-file.md b/src/sdk/documentation/general/dotnet-run-file.md index c2ae6b3261a..41bb96b5f6a 100644 --- a/src/sdk/documentation/general/dotnet-run-file.md +++ b/src/sdk/documentation/general/dotnet-run-file.md @@ -289,7 +289,8 @@ The build is performed using MSBuild APIs on in-memory project files. If an up-to-date check detects that inputs didn't change in subsequent `dotnet run file.cs` invocations, building is skipped (as if `--no-build` option has been passed). The up-to-date check is not 100% precise (e.g., files imported through an implicit build file are not considered). -It is possible to enforce a full build using `--no-cache` flag or `dotnet build file.cs`. +It is possible to enforce a full build using `--no-cache` flag or `dotnet build file.cs` +(for a more permanent opt-out, there is MSBuild property `FileBasedProgramCanSkipMSBuild=false`). Environment variable [`DOTNET_CLI_CONTEXT_VERBOSE=true`][verbose-env] can be used to get more details about caching decisions made by `dotnet run file.cs`. There are multiple optimization levels - skipping build altogether, running just the C# compiler, or running full MSBuild. @@ -297,8 +298,7 @@ We always need to re-run MSBuild if implicit build files like `Directory.Build.p from `.cs` files, the only relevant MSBuild inputs are the `#:` directives, hence we can first check the `.cs` file timestamps and for those that have changed, compare the sets of `#:` directives. If only `.cs` files change, it is enough to invoke `csc.exe` (directly or via a build server) -re-using command-line arguments that the last MSBuild invocation passed to the compiler -(you can opt out of this via an MSBuild property `FileBasedProgramCanSkipMSBuild=false`). +re-using command-line arguments that the last MSBuild invocation passed to the compiler. If no inputs change, it is enough to start the target executable without invoking the build at all. ## Alternatives and future work diff --git a/src/sdk/documentation/manpages/sdk/dotnet-build.1 b/src/sdk/documentation/manpages/sdk/dotnet-build.1 index 99fe1e65799..fb7ce595015 100644 --- a/src/sdk/documentation/manpages/sdk/dotnet-build.1 +++ b/src/sdk/documentation/manpages/sdk/dotnet-build.1 @@ -14,19 +14,19 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "dotnet-build" "1" "2025-06-13" "" ".NET Documentation" +.TH "dotnet-build" "1" "2025-09-30" "" ".NET Documentation" .hy .SH dotnet build .PP -\f[B]This article applies to:\f[R] \[u2714]\[uFE0F] .NET Core 3.1 SDK and later versions +\f[B]This article applies to:\f[R] \[u2714]\[uFE0F] .NET 6 and later versions .SH NAME .PP -dotnet-build - Builds a project and all of its dependencies. +dotnet-build - Builds a project, solution, or file-based app and all of its dependencies. .SH SYNOPSIS .IP .nf \f[C] -dotnet build [|] [-a|--arch ] +dotnet build [||] [-a|--arch ] [--artifacts-path ] [-c|--configuration ] [-f|--framework ] [--disable-build-servers] @@ -35,7 +35,7 @@ dotnet build [|] [-a|--arch ] [-o|--output ] [-p|--property:=] [-r|--runtime ] - [--self-contained [true|false]] [--source ] + [-sc|--self-contained [true|false]] [--source ] [--tl:[auto|on|off]] [--use-current-runtime, --ucr [true|false]] [-v|--verbosity ] [--version-suffix ] @@ -44,11 +44,11 @@ dotnet build -h|--help .fi .SH DESCRIPTION .PP -The \f[V]dotnet build\f[R] command builds the project and its dependencies into a set of binaries. +The \f[V]dotnet build\f[R] command builds the project, solution, or file-based app and its dependencies into a set of binaries. The binaries include the project\[cq]s code in Intermediate Language (IL) files with a \f[I].dll\f[R] extension. Depending on the project type and settings, other files may be included, such as: .IP \[bu] 2 -An executable that can be used to run the application, if the project type is an executable targeting .NET Core 3.0 or later. +An executable that can be used to run the application. .IP \[bu] 2 Symbol files used for debugging with a \f[I].pdb\f[R] extension. .IP \[bu] 2 @@ -58,12 +58,6 @@ A \f[I].runtimeconfig.json\f[R] file, which specifies the shared runtime and its .IP \[bu] 2 Other libraries that the project depends on (via project references or NuGet package references). .PP -For executable projects targeting versions earlier than .NET Core 3.0, library dependencies from NuGet are typically NOT copied to the output folder. -They\[cq]re resolved from the NuGet global packages folder at run time. -With that in mind, the product of \f[V]dotnet build\f[R] isn\[cq]t ready to be transferred to another machine to run. -To create a version of the application that can be deployed, you need to publish it (for example, with the dotnet publish command). -For more information, see .NET Application Deployment. -.PP For executable projects targeting .NET Core 3.0 and later, library dependencies are copied to the output folder. This means that if there isn\[cq]t any other publish-specific logic (such as Web projects have), the build output should be deployable. .SS Implicit restore @@ -98,7 +92,8 @@ To produce a library, omit the \f[V]\f[R] property or change its val The IL DLL for a library doesn\[cq]t contain entry points and can\[cq]t be executed. .SS MSBuild .PP -\f[V]dotnet build\f[R] uses MSBuild to build the project, so it supports both parallel and incremental builds. +\f[V]dotnet build\f[R] uses MSBuild to build the project, solution, or file-based app. +It supports both parallel and incremental builds. For more information, see Incremental Builds. .PP In addition to its options, the \f[V]dotnet build\f[R] command accepts MSBuild options, such as \f[V]-p\f[R] for setting properties or \f[V]-l\f[R] to define a logger. @@ -117,10 +112,19 @@ If the download is still running when this command finishes, the download is sto For more information, see Advertising manifests. .SH ARGUMENTS .PP -\f[V]PROJECT | SOLUTION\f[R] +\f[V]PROJECT | SOLUTION | FILE\f[R] .PP -The project or solution file to build. -If a project or solution file isn\[cq]t specified, MSBuild searches the current working directory for a file that has a file extension that ends in either \f[I]proj\f[R] or \f[I]sln\f[R] and uses that file. +The project or solution or C# (file-based app) file to operate on. +If a file isn\[cq]t specified, MSBuild searches the current directory for a project or solution. +.IP \[bu] 2 +\f[V]PROJECT\f[R] is the path and filename of a C#, F#, or Visual Basic project file, or the path to a directory that contains a C#, F#, or Visual Basic project file. +.IP \[bu] 2 +\f[V]SOLUTION\f[R] is the path and filename of a solution file (\f[I].sln\f[R] or \f[I].slnx\f[R] extension), or the path to a directory that contains a solution file. +.IP \[bu] 2 +\f[V]FILE\f[R] is an argument added in .NET 10. +The path and filename of a file-based app. +File-based apps are contained within a single file that is built and run without a corresponding project (\f[I].csproj\f[R]) file. +For more information, see Build file-based C# apps. .SH OPTIONS .IP \[bu] 2 \f[B]\f[VB]-a|--arch \f[B]\f[R] @@ -285,13 +289,13 @@ The URI of the NuGet package source to use during the restore operation. \f[B]\f[VB]--tl:[auto|on|off]\f[B]\f[R] .RS 2 .PP -Specifies whether the \f[I]terminal logger\f[R] should be used for the build output. +Specifies whether \f[I]Terminal Logger\f[R] should be used for the build output. The default is \f[V]auto\f[R], which first verifies the environment before enabling terminal logging. The environment check verifies that the terminal is capable of using modern output features and isn\[cq]t using a redirected standard output before enabling the new logger. \f[V]on\f[R] skips the environment check and enables terminal logging. \f[V]off\f[R] skips the environment check and uses the default console logger. .PP -The terminal logger shows you the restore phase followed by the build phase. +Terminal Logger shows you the restore phase followed by the build phase. During each phase, the currently building projects appear at the bottom of the terminal. Each project that\[cq]s building outputs both the MSBuild target currently being built and the amount of time spent on that target. You can search this information to learn more about the build. @@ -348,6 +352,18 @@ dotnet build .fi .RE .IP \[bu] 2 +Build a file-based app: +.RS 2 +.IP +.nf +\f[C] +dotnet build MyProject.cs +\f[R] +.fi +.PP +File-based app support was added in .NET SDK 10.0.100. +.RE +.IP \[bu] 2 Build a project and its dependencies using Release configuration: .RS 2 .IP diff --git a/src/sdk/documentation/manpages/sdk/dotnet-clean.1 b/src/sdk/documentation/manpages/sdk/dotnet-clean.1 index a259f0fe2df..d5968306997 100644 --- a/src/sdk/documentation/manpages/sdk/dotnet-clean.1 +++ b/src/sdk/documentation/manpages/sdk/dotnet-clean.1 @@ -14,11 +14,11 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "dotnet-clean" "1" "2025-06-13" "" ".NET Documentation" +.TH "dotnet-clean" "1" "2025-09-30" "" ".NET Documentation" .hy .SH dotnet clean .PP -\f[B]This article applies to:\f[R] \[u2714]\[uFE0F] .NET Core 3.1 SDK and later versions +\f[B]This article applies to:\f[R] \[u2714]\[uFE0F] .NET 6 and later versions .SH NAME .PP dotnet-clean - Cleans the output of a project. @@ -26,7 +26,7 @@ dotnet-clean - Cleans the output of a project. .IP .nf \f[C] -dotnet clean [|] [--artifacts-path ] +dotnet clean [||] [--artifacts-path ] [-c|--configuration ] [-f|--framework ] [--interactive] [--nologo] [-o|--output ] @@ -44,10 +44,19 @@ Only the outputs created during the build are cleaned. Both intermediate (\f[I]obj\f[R]) and final output (\f[I]bin\f[R]) folders are cleaned. .SH ARGUMENTS .PP -\f[V]PROJECT | SOLUTION\f[R] +\f[V]PROJECT | SOLUTION | FILE\f[R] .PP -The MSBuild project or solution to clean. -If a project or solution file is not specified, MSBuild searches the current working directory for a file that has a file extension that ends in \f[I]proj\f[R] or \f[I]sln\f[R], and uses that file. +The project or solution or C# (file-based app) file to operate on. +If a file isn\[cq]t specified, MSBuild searches the current directory for a project or solution. +.IP \[bu] 2 +\f[V]PROJECT\f[R] is the path and filename of a C#, F#, or Visual Basic project file, or the path to a directory that contains a C#, F#, or Visual Basic project file. +.IP \[bu] 2 +\f[V]SOLUTION\f[R] is the path and filename of a solution file (\f[I].sln\f[R] or \f[I].slnx\f[R] extension), or the path to a directory that contains a solution file. +.IP \[bu] 2 +\f[V]FILE\f[R] is an argument added in .NET 10. +The path and filename of a file-based app. +File-based apps are contained within a single file that is built and run without a corresponding project (\f[I].csproj\f[R]) file. +For more information, see Build file-based C# apps. .SH OPTIONS .IP \[bu] 2 \f[B]\f[VB]--artifacts-path \f[B]\f[R] @@ -119,13 +128,13 @@ This is used when a self-contained deployment was created. \f[B]\f[VB]--tl:[auto|on|off]\f[B]\f[R] .RS 2 .PP -Specifies whether the \f[I]terminal logger\f[R] should be used for the build output. +Specifies whether \f[I]Terminal Logger\f[R] should be used for the build output. The default is \f[V]auto\f[R], which first verifies the environment before enabling terminal logging. The environment check verifies that the terminal is capable of using modern output features and isn\[cq]t using a redirected standard output before enabling the new logger. \f[V]on\f[R] skips the environment check and enables terminal logging. \f[V]off\f[R] skips the environment check and uses the default console logger. .PP -The terminal logger shows you the restore phase followed by the build phase. +Terminal Logger shows you the restore phase followed by the build phase. During each phase, the currently building projects appear at the bottom of the terminal. Each project that\[cq]s building outputs both the MSBuild target currently being built and the amount of time spent on that target. You can search this information to learn more about the build. @@ -164,6 +173,18 @@ dotnet clean .fi .RE .IP \[bu] 2 +Clean a file-based program: +.RS 2 +.IP +.nf +\f[C] +dotnet clean Program.cs. +\f[R] +.fi +.PP +File-based app support was added in .NET SDK 10.0.100. +.RE +.IP \[bu] 2 Clean a project built using the Release configuration: .RS 2 .IP diff --git a/src/sdk/documentation/manpages/sdk/dotnet-pack.1 b/src/sdk/documentation/manpages/sdk/dotnet-pack.1 index 729fa6810b4..58e02e3e568 100644 --- a/src/sdk/documentation/manpages/sdk/dotnet-pack.1 +++ b/src/sdk/documentation/manpages/sdk/dotnet-pack.1 @@ -15,7 +15,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "dotnet-pack" "1" "2025-06-13" "" ".NET Documentation" +.TH "dotnet-pack" "1" "2025-09-30" "" ".NET Documentation" .hy .SH dotnet pack .PP @@ -202,13 +202,13 @@ For more information, see .NET Blog: .NET Framework 4.5.1 Supports Microsoft Sec \f[B]\f[VB]--tl:[auto|on|off]\f[B]\f[R] .RS 2 .PP -Specifies whether the \f[I]terminal logger\f[R] should be used for the build output. +Specifies whether \f[I]Terminal Logger\f[R] should be used for the build output. The default is \f[V]auto\f[R], which first verifies the environment before enabling terminal logging. The environment check verifies that the terminal is capable of using modern output features and isn\[cq]t using a redirected standard output before enabling the new logger. \f[V]on\f[R] skips the environment check and enables terminal logging. \f[V]off\f[R] skips the environment check and uses the default console logger. .PP -The terminal logger shows you the restore phase followed by the build phase. +Terminal Logger shows you the restore phase followed by the build phase. During each phase, the currently building projects appear at the bottom of the terminal. Each project that\[cq]s building outputs both the MSBuild target currently being built and the amount of time spent on that target. You can search this information to learn more about the build. diff --git a/src/sdk/documentation/manpages/sdk/dotnet-publish.1 b/src/sdk/documentation/manpages/sdk/dotnet-publish.1 index 64610ed4527..77da5ae6f4b 100644 --- a/src/sdk/documentation/manpages/sdk/dotnet-publish.1 +++ b/src/sdk/documentation/manpages/sdk/dotnet-publish.1 @@ -14,11 +14,11 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "dotnet-publish" "1" "2025-08-29" "" ".NET Documentation" +.TH "dotnet-publish" "1" "2025-09-30" "" ".NET Documentation" .hy .SH dotnet publish .PP -\f[B]This article applies to:\f[R] \[u2714]\[uFE0F] .NET Core 3.1 SDK and later versions +\f[B]This article applies to:\f[R] \[u2714]\[uFE0F] .NET 6 and later versions .SH NAME .PP dotnet-publish - Publishes the application and its dependencies to a folder for deployment to a hosting system. @@ -26,7 +26,7 @@ dotnet-publish - Publishes the application and its dependencies to a folder for .IP .nf \f[C] -dotnet publish [|] [-a|--arch ] +dotnet publish [||] [-a|--arch ] [--artifacts-path ] [-c|--configuration ] [--disable-build-servers] [-f|--framework ] [--force] [--interactive] @@ -172,18 +172,20 @@ When you run this command, it initiates an asynchronous background download of a If the download is still running when this command finishes, the download is stopped. For more information, see Advertising manifests. .SH ARGUMENTS -.IP \[bu] 2 -\f[B]\f[VB]PROJECT|SOLUTION\f[B]\f[R] -.RS 2 .PP -The project or solution to publish. +\f[V]PROJECT | SOLUTION | FILE\f[R] +.PP +The project or solution or C# (file-based app) file to operate on. +If a file isn\[cq]t specified, MSBuild searches the current directory for a project or solution. .IP \[bu] 2 \f[V]PROJECT\f[R] is the path and filename of a C#, F#, or Visual Basic project file, or the path to a directory that contains a C#, F#, or Visual Basic project file. -If the directory is not specified, it defaults to the current directory. .IP \[bu] 2 \f[V]SOLUTION\f[R] is the path and filename of a solution file (\f[I].sln\f[R] or \f[I].slnx\f[R] extension), or the path to a directory that contains a solution file. -If the directory is not specified, it defaults to the current directory. -.RE +.IP \[bu] 2 +\f[V]FILE\f[R] is an argument added in .NET 10. +The path and filename of a file-based app. +File-based apps are contained within a single file that is built and run without a corresponding project (\f[I].csproj\f[R]) file. +For more information, see Build file-based C# apps. .SH OPTIONS .IP \[bu] 2 \f[B]\f[VB]-a|--arch \f[B]\f[R] @@ -320,15 +322,6 @@ If you specify a relative path when publishing a solution, all output for all pr To make publish output go to separate folders for each project, specify a relative path by using the msbuild \f[V]PublishDir\f[R] property instead of the \f[V]--output\f[R] option. For example, \f[V]dotnet publish -p:PublishDir=.\[rs]publish\f[R] sends publish output for each project to a \f[V]publish\f[R] folder under the folder that contains the project file. .RE -.IP \[bu] 2 -\&.NET Core 2.x SDK -.RS 2 -.PP -If you specify a relative path when publishing a project, the generated output directory is relative to the project file location, not to the current working directory. -.PP -If you specify a relative path when publishing a solution, each project\[cq]s output goes into a separate folder relative to the project file location. -If you specify an absolute path when publishing a solution, all publish output for all projects goes into the specified folder. -.RE .RE .IP \[bu] 2 \f[B]\f[VB]--os \f[B]\f[R] @@ -376,13 +369,13 @@ If you use this option, use \f[V]--self-contained\f[R] or \f[V]--no-self-contain \f[B]\f[VB]--tl:[auto|on|off]\f[B]\f[R] .RS 2 .PP -Specifies whether the \f[I]terminal logger\f[R] should be used for the build output. +Specifies whether \f[I]Terminal Logger\f[R] should be used for the build output. The default is \f[V]auto\f[R], which first verifies the environment before enabling terminal logging. The environment check verifies that the terminal is capable of using modern output features and isn\[cq]t using a redirected standard output before enabling the new logger. \f[V]on\f[R] skips the environment check and enables terminal logging. \f[V]off\f[R] skips the environment check and uses the default console logger. .PP -The terminal logger shows you the restore phase followed by the build phase. +Terminal Logger shows you the restore phase followed by the build phase. During each phase, the currently building projects appear at the bottom of the terminal. Each project that\[cq]s building outputs both the MSBuild target currently being built and the amount of time spent on that target. You can search this information to learn more about the build. @@ -491,6 +484,18 @@ dotnet publish --no-dependencies \f[R] .fi .RE +.IP \[bu] 2 +Publish the file-based C# program \f[I]app.cs\f[R] in the current directory: +.RS 2 +.IP +.nf +\f[C] +dotnet publish app.cs +\f[R] +.fi +.PP +File-based program support was added in .NET SDK 10.0.100. +.RE .SH SEE ALSO .IP \[bu] 2 \&.NET application publishing overview diff --git a/src/sdk/documentation/manpages/sdk/dotnet-restore.1 b/src/sdk/documentation/manpages/sdk/dotnet-restore.1 index 498f0b210e8..334fba4e4b1 100644 --- a/src/sdk/documentation/manpages/sdk/dotnet-restore.1 +++ b/src/sdk/documentation/manpages/sdk/dotnet-restore.1 @@ -14,11 +14,11 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "dotnet-restore" "1" "2025-06-30" "" ".NET Documentation" +.TH "dotnet-restore" "1" "2025-09-30" "" ".NET Documentation" .hy .SH dotnet restore .PP -\f[B]This article applies to:\f[R] \[u2714]\[uFE0F] .NET Core 3.1 SDK and later versions +\f[B]This article applies to:\f[R] \[u2714]\[uFE0F] .NET 6 and later versions .SH NAME .PP dotnet-restore - Restores the dependencies and tools of a project. @@ -26,7 +26,7 @@ dotnet-restore - Restores the dependencies and tools of a project. .IP .nf \f[C] -dotnet restore [] [--configfile ] [--disable-build-servers] +dotnet restore [||] [--configfile ] [--disable-build-servers] [--disable-parallel] [-f|--force] [--force-evaluate] [--ignore-failed-sources] [--interactive] [--lock-file-path ] [--locked-mode] @@ -126,12 +126,20 @@ When you run this command, it initiates an asynchronous background download of a If the download is still running when this command finishes, the download is stopped. For more information, see Advertising manifests. .SH ARGUMENTS -.IP \[bu] 2 -\f[B]\f[VB]ROOT\f[B]\f[R] -.RS 2 .PP -Optional path to the project file to restore. -.RE +\f[V]PROJECT | SOLUTION | FILE\f[R] +.PP +The project or solution or C# (file-based app) file to operate on. +If a file isn\[cq]t specified, MSBuild searches the current directory for a project or solution. +.IP \[bu] 2 +\f[V]PROJECT\f[R] is the path and filename of a C#, F#, or Visual Basic project file, or the path to a directory that contains a C#, F#, or Visual Basic project file. +.IP \[bu] 2 +\f[V]SOLUTION\f[R] is the path and filename of a solution file (\f[I].sln\f[R] or \f[I].slnx\f[R] extension), or the path to a directory that contains a solution file. +.IP \[bu] 2 +\f[V]FILE\f[R] is an argument added in .NET 10. +The path and filename of a file-based app. +File-based apps are contained within a single file that is built and run without a corresponding project (\f[I].csproj\f[R]) file. +For more information, see Build file-based C# apps. .SH OPTIONS .IP \[bu] 2 \f[B]\f[VB]-a|--arch \f[B]\f[R] @@ -250,13 +258,13 @@ Multiple sources can be provided by specifying this option multiple times. \f[B]\f[VB]--tl:[auto|on|off]\f[B]\f[R] .RS 2 .PP -Specifies whether the \f[I]terminal logger\f[R] should be used for the build output. +Specifies whether \f[I]Terminal Logger\f[R] should be used for the build output. The default is \f[V]auto\f[R], which first verifies the environment before enabling terminal logging. The environment check verifies that the terminal is capable of using modern output features and isn\[cq]t using a redirected standard output before enabling the new logger. \f[V]on\f[R] skips the environment check and enables terminal logging. \f[V]off\f[R] skips the environment check and uses the default console logger. .PP -The terminal logger shows you the restore phase followed by the build phase. +Terminal Logger shows you the restore phase followed by the build phase. During each phase, the currently building projects appear at the bottom of the terminal. Each project that\[cq]s building outputs both the MSBuild target currently being built and the amount of time spent on that target. You can search this information to learn more about the build. diff --git a/src/sdk/documentation/manpages/sdk/dotnet-run.1 b/src/sdk/documentation/manpages/sdk/dotnet-run.1 index 65cf2e8d10a..c37a294d9f8 100644 --- a/src/sdk/documentation/manpages/sdk/dotnet-run.1 +++ b/src/sdk/documentation/manpages/sdk/dotnet-run.1 @@ -14,11 +14,11 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "dotnet-run" "1" "2025-06-13" "" ".NET Documentation" +.TH "dotnet-run" "1" "2025-09-30" "" ".NET Documentation" .hy .SH dotnet run .PP -\f[B]This article applies to:\f[R] \[u2714]\[uFE0F] .NET Core 3.1 SDK and later versions +\f[B]This article applies to:\f[R] \[u2714]\[uFE0F] .NET 6 and later versions .SH NAME .PP dotnet-run - Runs source code without any explicit compile or launch commands. @@ -26,8 +26,8 @@ dotnet-run - Runs source code without any explicit compile or launch commands. .IP .nf \f[C] -dotnet run [-a|--arch ] [-c|--configuration ] - [-e|--environment ] +dotnet run [] [-a|--arch ] [-c|--configuration ] + [-e|--environment ] [--file ] [-f|--framework ] [--force] [--interactive] [--launch-profile ] [--no-build] [--no-dependencies] [--no-launch-profile] [--no-restore] @@ -87,6 +87,14 @@ Short form options, such as \f[V]-s\f[R], are not supported. When you run this command, it initiates an asynchronous background download of advertising manifests for workloads. If the download is still running when this command finishes, the download is stopped. For more information, see Advertising manifests. +.SH ARGUMENTS +.PP +\f[V]\f[R] +.PP +Arguments passed to the application that is being run. +.PP +Any arguments that aren\[cq]t recognized by \f[V]dotnet run\f[R] are passed to the application. +To separate arguments for \f[V]dotnet run\f[R] from arguments for the application, use the \f[V]--\f[R] option. .SH OPTIONS .IP \[bu] 2 \f[B]\f[VB]--\f[B]\f[R] @@ -132,6 +140,34 @@ Builds and runs the app using the specified framework. The framework must be specified in the project file. .RE .IP \[bu] 2 +\f[B]\f[VB]--file \f[B]\f[R] +.RS 2 +.PP +The path to the file-based app to run. +If a path isn\[cq]t specified, the current directory is used to find and run the file. +For more information on file-based apps, see Build file-based C# apps. +.PP +On Unix, you can run file-based apps directly, using the source file name on the command line instead of \f[V]dotnet run\f[R]. +First, ensure the file has execute permissions. +Then, add a shebang line \f[V]#!\f[R] as the first line of the file, for example: +.IP +.nf +\f[C] +#!/usr/bin/env dotnet run +\f[R] +.fi +.PP +Then you can run the file directly from the command line: +.IP +.nf +\f[C] +\&./ConsoleApp.cs +\f[R] +.fi +.PP +Introduced in .NET SDK 10.0.100. +.RE +.IP \[bu] 2 \f[B]\f[VB]--force\f[B]\f[R] .RS 2 .PP @@ -245,13 +281,13 @@ For a list of Runtime Identifiers (RIDs), see the RID catalog. \f[B]\f[VB]--tl:[auto|on|off]\f[B]\f[R] .RS 2 .PP -Specifies whether the \f[I]terminal logger\f[R] should be used for the build output. +Specifies whether \f[I]Terminal Logger\f[R] should be used for the build output. The default is \f[V]auto\f[R], which first verifies the environment before enabling terminal logging. The environment check verifies that the terminal is capable of using modern output features and isn\[cq]t using a redirected standard output before enabling the new logger. \f[V]on\f[R] skips the environment check and enables terminal logging. \f[V]off\f[R] skips the environment check and uses the default console logger. .PP -The terminal logger shows you the restore phase followed by the build phase. +Terminal Logger shows you the restore phase followed by the build phase. During each phase, the currently building projects appear at the bottom of the terminal. Each project that\[cq]s building outputs both the MSBuild target currently being built and the amount of time spent on that target. You can search this information to learn more about the build. @@ -306,6 +342,18 @@ dotnet run .fi .RE .IP \[bu] 2 +Run the specified file-based app in the current directory: +.RS 2 +.IP +.nf +\f[C] +dotnet run --file ConsoleApp.cs +\f[R] +.fi +.PP +File-based app support was added in .NET SDK 10.0.100. +.RE +.IP \[bu] 2 Run the specified project: .RS 2 .IP @@ -345,3 +393,22 @@ dotnet run --verbosity m \f[R] .fi .RE +.IP \[bu] 2 +Run the project in the current directory using the specified framework and pass arguments to the application: +.RS 2 +.IP +.nf +\f[C] +dotnet run -f net6.0 -- arg1 arg2 +\f[R] +.fi +.PP +In the following example, three arguments are passed to the application. +One argument is passed using \f[V]-\f[R], and two arguments are passed after \f[V]--\f[R]: +.IP +.nf +\f[C] +dotnet run -f net6.0 -arg1 -- arg2 arg3 +\f[R] +.fi +.RE diff --git a/src/sdk/documentation/manpages/sdk/dotnet-watch.1 b/src/sdk/documentation/manpages/sdk/dotnet-watch.1 index 6a02e55593a..538a5acd063 100644 --- a/src/sdk/documentation/manpages/sdk/dotnet-watch.1 +++ b/src/sdk/documentation/manpages/sdk/dotnet-watch.1 @@ -14,7 +14,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "dotnet-watch" "1" "2025-06-13" "" ".NET Documentation" +.TH "dotnet-watch" "1" "2025-09-30" "" ".NET Documentation" .hy .SH dotnet watch .PP @@ -177,7 +177,7 @@ The class uses \f \f[B]\f[VB]DOTNET_WATCH_AUTO_RELOAD_WS_HOSTNAME\f[B]\f[R] .RS 2 .PP -As part of \f[V]dotnet watch\f[R], the browser refresh server mechanism reads this value to determine the WebSocket host environment's hostname. +As part of \f[V]dotnet watch\f[R], the browser refresh server mechanism reads this value to determine the WebSocket host environment. The value \f[V]127.0.0.1\f[R] is replaced by \f[V]localhost\f[R], and the \f[V]http://\f[R] and \f[V]https://\f[R] schemes are replaced with \f[V]ws://\f[R] and \f[V]wss://\f[R] respectively. .RE .IP \[bu] 2 diff --git a/src/sdk/documentation/project-docs/telemetry.md b/src/sdk/documentation/project-docs/telemetry.md index 4e73f8c0f6a..e559f60bb25 100644 --- a/src/sdk/documentation/project-docs/telemetry.md +++ b/src/sdk/documentation/project-docs/telemetry.md @@ -1,6 +1,7 @@ # .NET SDK Telemetry Documentation ## Table of Contents + - [.NET SDK Telemetry Documentation](#net-sdk-telemetry-documentation) - [Table of Contents](#table-of-contents) - [How to Control Telemetry](#how-to-control-telemetry) @@ -25,7 +26,6 @@ The .NET SDK telemetry can be disabled using the following environment variable: - Example: `set DOTNET_CLI_TELEMETRY_OPTOUT=1` (Windows) - Note: this value is defaulted to `true` on non-Microsoft-provided builds of the .NET SDK (e.g. those provided by our Linux Distro partners, through Source Build, etc.) - ### Related Environment Variables - **`DOTNET_NOLOGO`**: Set to `true` to hide .NET welcome and telemetry messages on first run @@ -40,7 +40,6 @@ The .NET SDK telemetry can be disabled using the following environment variable: - For Microsoft official builds: Telemetry is **enabled by default** (opt-out model) - For non-Microsoft builds: Telemetry is **disabled by default** (controlled by `MICROSOFT_ENABLE_TELEMETRY` compile flag) - - **Connection String**: Telemetry data is sent to Application Insights with instrumentation key: `74cc1c9e-3e6e-4d05-b3fc-dde9101d0254` - **First Time Use**: Telemetry is only collected after the first-time-use notice has been shown and accepted (tracked via sentinel file) @@ -51,8 +50,6 @@ The .NET SDK telemetry can be disabled using the following environment variable: Every telemetry event automatically includes these common properties: - - | Property | Description | Example Value | |----------|-------------|---------------| | **OS Version** | Operating system version | `Microsoft Windows 10.0.14393` | @@ -64,6 +61,7 @@ Every telemetry event automatically includes these common properties: | **Telemetry Profile** | Custom telemetry profile (if set via env var) | Custom value or null | | **Docker Container** | Whether running in Docker container | `True` or `False` | | **CI** | Whether running in CI environment | `True` or `False` | +| **LLM** | Detected LLM/assistant environment identifiers (comma-separated) | `claude`, `cursor`, `gemini`, `copilot`, `generic_agent` | | **Current Path Hash** | SHA256 hash of current directory path | Hashed value | | **Machine ID** | SHA256 hash of machine MAC address (or GUID if unavailable) | Hashed value | | **Machine ID Old** | Legacy machine ID for compatibility | Hashed value | @@ -80,9 +78,11 @@ Every telemetry event automatically includes these common properties: ### Core CLI Events #### `command/finish` + **When fired**: At the end of every dotnet CLI command execution **Properties**: + - `exitCode`: The exit code of the command **Description**: Tracks the completion status of any dotnet command @@ -90,9 +90,11 @@ Every telemetry event automatically includes these common properties: --- #### `schema` + **When fired**: When CLI schema is generated or accessed **Properties**: + - `command`: The command hierarchy as a string **Description**: Tracks schema generation for the CLI @@ -100,9 +102,11 @@ Every telemetry event automatically includes these common properties: --- #### `toplevelparser/command` + **When fired**: For every top-level dotnet command **Properties**: + - `verb`: Top-level command name (build, restore, publish, etc.) **Measurements**: Performance data (startup time, parse time, etc.) @@ -112,6 +116,7 @@ Every telemetry event automatically includes these common properties: --- #### `sublevelparser/command` + **When fired**: For subcommands and specific command options **Properties**: Various depending on command (verbosity, configuration, framework, etc.) @@ -121,9 +126,11 @@ Every telemetry event automatically includes these common properties: --- #### `commandresolution/commandresolved` + **When fired**: When a command is resolved through the command factory **Properties**: + - `commandName`: SHA256 hash of command name - `commandResolver`: Type of command resolver used @@ -132,9 +139,11 @@ Every telemetry event automatically includes these common properties: --- #### `install/reportsuccess` + **When fired**: When installation success is reported **Properties**: + - `exeName`: Name of the install method that was used - one of `debianpackage`, a specific macOS `.pkg` file name, or a specific Windows exe installer file name. **Description**: Tracks successful tool installations @@ -142,9 +151,11 @@ Every telemetry event automatically includes these common properties: --- #### `mainCatchException/exception` + **When fired**: When unhandled exceptions occur in the main CLI **Properties**: + - `exceptionType`: Type of exception - `detail`: Exception details (sensitive message removed) @@ -153,9 +164,11 @@ Every telemetry event automatically includes these common properties: ### Template Engine Events #### `template/new-install` + **When fired**: During template package installation **Properties**: + - `CountOfThingsToInstall`: Number of template packages being installed **Description**: Tracks template package installation operations @@ -163,9 +176,11 @@ Every telemetry event automatically includes these common properties: --- #### `template/new-create-template` + **When fired**: When creating a new project from template **Properties**: + - `language`: Template language (C#, F#, VB, etc) - `argument-error`: Whether there were argument errors ("True"/"False") - `framework`: Framework choice (only sent for Microsoft-authored templates) @@ -182,9 +197,11 @@ Every telemetry event automatically includes these common properties: ### SDK-Collected Build Events #### `msbuild/targetframeworkeval` + **When fired**: When target framework is evaluated **Properties**: + - `TargetFrameworkVersion`: Target framework version - `RuntimeIdentifier`: Runtime identifier - `SelfContained`: Whether self-contained @@ -197,11 +214,12 @@ Every telemetry event automatically includes these common properties: --- - #### `taskBaseCatchException` + **When fired**: When exceptions occur in SDK-provided MSBuild tasks **Properties**: + - `exceptionType`: Exception type - `detail`: Exception details (message removed) @@ -210,53 +228,60 @@ Every telemetry event automatically includes these common properties: --- #### `PublishProperties` + **When fired**: During the Publish Target **Properties**: Gathers the values of the following MSBuild Properties if they are set in the project file or via command line: -* PublishReadyToRun -* PublishSingleFile -* PublishTrimmed -* PublishAot -* PublishProtocol + +- PublishReadyToRun +- PublishSingleFile +- PublishTrimmed +- PublishAot +- PublishProtocol **Description**: Tracks publish-related properties --- #### `WorkloadPublishProperties` + **When fired**: During workload publish operations **Properties**: Gathers the values of the following MSBuild Properties if they are set in the project file or via command line: -* TargetPlatformIdentifier: TargetPlatformIdentifier -* RuntimeIdentifier: RuntimeIdentifier -* BlazorWasm: _WorkloadUsesBlazorWasm -* WasmSDK: _WorkloadUsesWasmSDK -* UsesMaui: UseMaui -* UsesMobileSDKOnly: _WorkloadUsesMobileSDKOnly -* UsesOtherMobileSDK: _WorkloadUsesOther -* MonoAOT: _WorkloadUsesMonoAOT -* NativeAOT: _WorkloadUsesNativeAOT -* Interp: _WorkloadUsesInterpreter -* LibraryMode: _WorkloadUsesLibraryMode -* ResolvedRuntimePack: _MonoWorkloadRuntimePackPackageVersion -* StripILAfterAOT: _WorkloadUsesStripILAfterAOT + +- TargetPlatformIdentifier: TargetPlatformIdentifier +- RuntimeIdentifier: RuntimeIdentifier +- BlazorWasm: _WorkloadUsesBlazorWasm +- WasmSDK: _WorkloadUsesWasmSDK +- UsesMaui: UseMaui +- UsesMobileSDKOnly: _WorkloadUsesMobileSDKOnly +- UsesOtherMobileSDK: _WorkloadUsesOther +- MonoAOT: _WorkloadUsesMonoAOT +- NativeAOT: _WorkloadUsesNativeAOT +- Interp: _WorkloadUsesInterpreter +- LibraryMode: _WorkloadUsesLibraryMode +- ResolvedRuntimePack: _MonoWorkloadRuntimePackPackageVersion +- StripILAfterAOT: _WorkloadUsesStripILAfterAOT **Description**: Tracks workload-specific publish properties --- #### `ReadyToRun` + **When fired**: During ReadyToRun compilation **Properties**: Gathers the values of the following MSBuild Properties and Items if they are set in the project file or via command line: -* PublishReadyToRunUseCrossgen2: PublishReadyToRunUseCrossgen2 -* Crossgen2PackVersion: ResolvedCrossgen2Pack.NuGetPackageVersion -* CompileListCount: _ReadyToRunCompileList->Count() -* FailedCount: _ReadyToRunCompilationFailures->Count() +- PublishReadyToRunUseCrossgen2: PublishReadyToRunUseCrossgen2 +- Crossgen2PackVersion: ResolvedCrossgen2Pack.NuGetPackageVersion +- CompileListCount: _ReadyToRunCompileList->Count() +- FailedCount: _ReadyToRunCompilationFailures->Count() **Description**: Tracks ReadyToRun compilation usage +--- + ### MSBuild Engine Telemetry See [MSBuild Telemetry Documentation](https://github.com/dotnet/msbuild/blob/main/documentation/wiki/CollectedTelemetry.md) for details on these events. @@ -268,15 +293,18 @@ See [Container Telemetry Documentation](https://github.com/dotnet/sdk-container- ### `dotnet new` Command MSBuild Evaluation #### `new/msbuild-eval` + **When fired**: When MSBuild project evaluation occurs during `dotnet new` **Properties** (hashed): + - `ProjectPath`: Project path - `SdkStyleProject`: Whether it's SDK-style project - `Status`: Evaluation status - `TargetFrameworks`: Target frameworks **Measurements**: + - `EvaluationTime`: Total evaluation time in milliseconds - `InnerEvaluationTime`: Inner evaluation time in milliseconds @@ -284,7 +312,7 @@ See [Container Telemetry Documentation](https://github.com/dotnet/sdk-container- ## How to update this document -* Ensure that all telemetry events and properties are accurately documented -* Review and update common properties as needed -* Add new events or properties as they are introduced in the .NET SDK -* Follow the pre-existing format +- Ensure that all telemetry events and properties are accurately documented +- Review and update common properties as needed +- Add new events or properties as they are introduced in the .NET SDK +- Follow the pre-existing format diff --git a/src/sdk/eng/Version.Details.props b/src/sdk/eng/Version.Details.props index d0f9c7079cc..9fa33977310 100644 --- a/src/sdk/eng/Version.Details.props +++ b/src/sdk/eng/Version.Details.props @@ -6,142 +6,142 @@ This file should be imported by eng/Versions.props - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-preview.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 17.15.0-preview-25460-104 - 17.15.0-preview-25460-104 - 7.0.0-preview.1.46104 - 10.0.0-beta.25460.104 - 5.0.0-2.25460.104 - 5.0.0-2.25460.104 - 5.0.0-2.25460.104 - 5.0.0-2.25460.104 - 5.0.0-2.25460.104 - 5.0.0-2.25460.104 - 5.0.0-2.25460.104 - 10.0.0-preview.25460.104 - 5.0.0-2.25460.104 - 5.0.0-2.25460.104 - 2.0.0-preview.1.25460.104 - 2.2.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 14.0.100-rc2.25460.104 - 10.0.0-rc.2.25460.104 - 5.0.0-2.25460.104 - 5.0.0-2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-preview.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 18.0.0-preview-25467-107 + 18.0.0-preview-25467-107 + 7.0.0-preview.2.46807 + 10.0.0-beta.25467.107 + 5.0.0-2.25467.107 + 5.0.0-2.25467.107 + 5.0.0-2.25467.107 + 5.0.0-2.25467.107 + 5.0.0-2.25467.107 + 5.0.0-2.25467.107 + 5.0.0-2.25467.107 + 10.0.0-preview.25467.107 + 5.0.0-2.25467.107 + 5.0.0-2.25467.107 + 2.0.0-preview.1.25467.107 + 2.2.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 14.0.100-rc2.25467.107 + 10.0.0-rc.2.25467.107 + 5.0.0-2.25467.107 + 5.0.0-2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 10.0.0-preview.7.25377.103 - 10.0.0-preview.25460.104 - 10.0.0-rc.2.25460.104 - 18.0.0-preview-25460-104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.0-beta.25460.104 - 10.0.100-rc.2.25460.104 - 10.0.100-rc.2.25460.104 - 10.0.100-rc.2.25460.104 - 10.0.100-rc.2.25460.104 - 10.0.100-rc.2.25460.104 - 10.0.100-rc.2.25460.104 - 10.0.100-rc.2.25460.104 - 10.0.100-rc.2.25460.104 - 10.0.100-rc.2.25460.104 - 18.0.0-preview-25460-104 - 18.0.0-preview-25460-104 - 3.2.0-preview.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 7.0.0-preview.1.46104 - 10.0.0-rc.2.25460.104 - 2.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 - 10.0.0-rc.2.25460.104 + 10.0.0-preview.25467.107 + 10.0.0-rc.2.25467.107 + 18.0.0-preview-25467-107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.0-beta.25467.107 + 10.0.100-rc.2.25467.107 + 10.0.100-rc.2.25467.107 + 10.0.100-rc.2.25467.107 + 10.0.100-rc.2.25467.107 + 10.0.100-rc.2.25467.107 + 10.0.100-rc.2.25467.107 + 10.0.100-rc.2.25467.107 + 10.0.100-rc.2.25467.107 + 10.0.100-rc.2.25467.107 + 18.0.0-preview-25467-107 + 18.0.0-preview-25467-107 + 3.2.0-preview.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 7.0.0-preview.2.46807 + 10.0.0-rc.2.25467.107 + 2.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 + 10.0.0-rc.2.25467.107 2.1.0 - 1.9.0-preview.25467.1 - 3.11.0-preview.25467.1 + 1.9.0-preview.25475.1 + 3.11.0-preview.25475.1 diff --git a/src/sdk/eng/Version.Details.xml b/src/sdk/eng/Version.Details.xml index 32c14616bad..6f095d0867f 100644 --- a/src/sdk/eng/Version.Details.xml +++ b/src/sdk/eng/Version.Details.xml @@ -1,62 +1,62 @@ - + - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 @@ -68,166 +68,166 @@ https://github.com/dotnet/dotnet 6a953e76162f3f079405f80e28664fa51b136740 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 - + https://github.com/microsoft/testfx - a65b77ad062d0a16ecd9452b828174d9efa8c89f + 74721fc4a96eefb3b757e3ffacaae1fdcbe7a0f8 - + https://github.com/microsoft/testfx - a65b77ad062d0a16ecd9452b828174d9efa8c89f + 74721fc4a96eefb3b757e3ffacaae1fdcbe7a0f8 - + https://github.com/dotnet/dotnet - eac14590f69f6876d418cef9e8fdd3f44f6ef0b2 + e533cfad385ba4f0ec96e35ad3d485dc13581906 diff --git a/src/sdk/eng/common/SetupNugetSources.ps1 b/src/sdk/eng/common/SetupNugetSources.ps1 index 792b60b49d4..9445c314325 100644 --- a/src/sdk/eng/common/SetupNugetSources.ps1 +++ b/src/sdk/eng/common/SetupNugetSources.ps1 @@ -157,7 +157,7 @@ if ($dotnet31Source -ne $null) { AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2" -Creds $creds -Username $userName -pwd $Password } -$dotnetVersions = @('5','6','7','8','9') +$dotnetVersions = @('5','6','7','8','9','10') foreach ($dotnetVersion in $dotnetVersions) { $feedPrefix = "dotnet" + $dotnetVersion; diff --git a/src/sdk/eng/common/SetupNugetSources.sh b/src/sdk/eng/common/SetupNugetSources.sh index facb415ca6f..ddf4efc81a4 100755 --- a/src/sdk/eng/common/SetupNugetSources.sh +++ b/src/sdk/eng/common/SetupNugetSources.sh @@ -99,7 +99,7 @@ if [ "$?" == "0" ]; then PackageSources+=('dotnet3.1-internal-transport') fi -DotNetVersions=('5' '6' '7' '8' '9') +DotNetVersions=('5' '6' '7' '8' '9' '10') for DotNetVersion in ${DotNetVersions[@]} ; do FeedPrefix="dotnet${DotNetVersion}"; diff --git a/src/sdk/eng/common/core-templates/job/publish-build-assets.yml b/src/sdk/eng/common/core-templates/job/publish-build-assets.yml index aba50e34103..348cd16376f 100644 --- a/src/sdk/eng/common/core-templates/job/publish-build-assets.yml +++ b/src/sdk/eng/common/core-templates/job/publish-build-assets.yml @@ -40,8 +40,6 @@ parameters: repositoryAlias: self - officialBuildId: '' - jobs: - job: Asset_Registry_Publish @@ -64,11 +62,6 @@ jobs: value: false # unconditional - needed for logs publishing (redactor tool version) - template: /eng/common/core-templates/post-build/common-variables.yml - - name: OfficialBuildId - ${{ if ne(parameters.officialBuildId, '') }}: - value: ${{ parameters.officialBuildId }} - ${{ else }}: - value: $(Build.BuildNumber) pool: # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) diff --git a/src/sdk/eng/common/core-templates/job/source-build.yml b/src/sdk/eng/common/core-templates/job/source-build.yml index 947f0971eb5..d805d5faeb9 100644 --- a/src/sdk/eng/common/core-templates/job/source-build.yml +++ b/src/sdk/eng/common/core-templates/job/source-build.yml @@ -34,9 +34,6 @@ parameters: # container and pool. platform: {} - # Optional list of directories to ignore for component governance scans. - componentGovernanceIgnoreDirectories: [] - is1ESPipeline: '' # If set to true and running on a non-public project, @@ -97,4 +94,3 @@ jobs: parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} platform: ${{ parameters.platform }} - componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} diff --git a/src/sdk/eng/common/core-templates/jobs/jobs.yml b/src/sdk/eng/common/core-templates/jobs/jobs.yml index 01ada747665..b637cb6e948 100644 --- a/src/sdk/eng/common/core-templates/jobs/jobs.yml +++ b/src/sdk/eng/common/core-templates/jobs/jobs.yml @@ -44,7 +44,6 @@ parameters: artifacts: {} is1ESPipeline: '' repositoryAlias: self - officialBuildId: '' # Internal resources (telemetry, microbuild) can only be accessed from non-public projects, # and some (Microbuild) should only be applied to non-PR cases for internal builds. @@ -117,4 +116,3 @@ jobs: artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} signingValidationAdditionalParameters: ${{ parameters.signingValidationAdditionalParameters }} repositoryAlias: ${{ parameters.repositoryAlias }} - officialBuildId: ${{ parameters.officialBuildId }} diff --git a/src/sdk/eng/common/core-templates/jobs/source-build.yml b/src/sdk/eng/common/core-templates/jobs/source-build.yml index eb4b923a777..d92860cba20 100644 --- a/src/sdk/eng/common/core-templates/jobs/source-build.yml +++ b/src/sdk/eng/common/core-templates/jobs/source-build.yml @@ -15,9 +15,6 @@ parameters: # one job runs on 'defaultManagedPlatform'. platforms: [] - # Optional list of directories to ignore for component governance scans. - componentGovernanceIgnoreDirectories: [] - is1ESPipeline: '' # If set to true and running on a non-public project, @@ -34,7 +31,6 @@ jobs: is1ESPipeline: ${{ parameters.is1ESPipeline }} jobNamePrefix: ${{ parameters.jobNamePrefix }} platform: ${{ platform }} - componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} enableInternalSources: ${{ parameters.enableInternalSources }} - ${{ if eq(length(parameters.platforms), 0) }}: @@ -43,5 +39,4 @@ jobs: is1ESPipeline: ${{ parameters.is1ESPipeline }} jobNamePrefix: ${{ parameters.jobNamePrefix }} platform: ${{ parameters.defaultManagedPlatform }} - componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} enableInternalSources: ${{ parameters.enableInternalSources }} diff --git a/src/sdk/eng/common/core-templates/steps/source-build.yml b/src/sdk/eng/common/core-templates/steps/source-build.yml index 77321eee11f..acf16ed3496 100644 --- a/src/sdk/eng/common/core-templates/steps/source-build.yml +++ b/src/sdk/eng/common/core-templates/steps/source-build.yml @@ -11,10 +11,6 @@ parameters: # for details. The entire object is described in the 'job' template for simplicity, even though # the usage of the properties on this object is split between the 'job' and 'steps' templates. platform: {} - - # Optional list of directories to ignore for component governance scans. - componentGovernanceIgnoreDirectories: [] - is1ESPipeline: false steps: diff --git a/src/sdk/eng/dotnet-format/dotnet-format-integration.yml b/src/sdk/eng/dotnet-format/dotnet-format-integration.yml index 1fa8bbb8ad9..25c17948bf5 100644 --- a/src/sdk/eng/dotnet-format/dotnet-format-integration.yml +++ b/src/sdk/eng/dotnet-format/dotnet-format-integration.yml @@ -2,6 +2,7 @@ parameters: - name: oneESCompat type: object default: + templateFolderName: templates publishTaskPrefix: '' - name: TestArguments @@ -63,6 +64,9 @@ parameters: - name: runtimeSourceProperties type: string default: '' +- name: populateInternalRuntimeVariables + type: boolean + default: false jobs: - job: Formatting_Check @@ -77,8 +81,11 @@ jobs: os: windows timeoutInMinutes: ${{ parameters.timeoutInMinutes }} steps: - - template: /eng/common/templates/steps/enable-internal-runtimes.yml - - template: /eng/common/templates/steps/enable-internal-sources.yml + - ${{ if eq(parameters.populateInternalRuntimeVariables, true) }}: + - template: /eng/common/${{ parameters.oneESCompat.templateFolderName }}/steps/enable-internal-sources.yml + parameters: + legacyCredential: $(dn-bot-dnceng-artifact-feeds-rw) + - template: /eng/common/${{ parameters.oneESCompat.templateFolderName }}/steps/enable-internal-runtimes.yml - script: .\restore.cmd ${{ parameters.runtimeSourceProperties }} displayName: 🟣 Restore dependencies - script: | @@ -106,8 +113,11 @@ jobs: os: windows timeoutInMinutes: ${{ parameters.timeoutInMinutes }} steps: - - template: /eng/common/templates/steps/enable-internal-runtimes.yml - - template: /eng/common/templates/steps/enable-internal-sources.yml + - ${{ if eq(parameters.populateInternalRuntimeVariables, true) }}: + - template: /eng/common/${{ parameters.oneESCompat.templateFolderName }}/steps/enable-internal-sources.yml + parameters: + legacyCredential: $(dn-bot-dnceng-artifact-feeds-rw) + - template: /eng/common/${{ parameters.oneESCompat.templateFolderName }}/steps/enable-internal-runtimes.yml - script: eng\dotnet-format\integration-test.cmd -repo '${{ testArgs._repo }}' -branchName '${{ testArgs._branchName }}' -sha '${{ testArgs._sha }}' -targetSolution '${{ testArgs._targetSolution }}' -useParentSdk ${{ testArgs._useParentSdk }} -testPath '$(Agent.TempDirectory)\temp' -stage 'prepare' -runtimeSourceProperties '${{ parameters.runtimeSourceProperties }}' displayName: 🟣 Prepare ${{ testArgs._repoName }} for formatting diff --git a/src/sdk/eng/pipelines/templates/jobs/sdk-build.yml b/src/sdk/eng/pipelines/templates/jobs/sdk-build.yml index 202d480959a..a9fc3537bfc 100644 --- a/src/sdk/eng/pipelines/templates/jobs/sdk-build.yml +++ b/src/sdk/eng/pipelines/templates/jobs/sdk-build.yml @@ -12,7 +12,9 @@ parameters: testProjects: $(Build.SourcesDirectory)/test/UnitTests.proj publishRetryConfig: false publishXunitResults: false + testRunnerAdditionalArguments: '' enableSbom: true + populateInternalRuntimeVariables: false timeoutInMinutes: 150 ### ENV VARS ### testFullMSBuild: false @@ -71,11 +73,11 @@ jobs: targetPath: $(Build.SourcesDirectory)/eng/BuildConfiguration artifactName: BuildConfiguration - # Populate internal runtime variables. - - template: /eng/common/templates/steps/enable-internal-sources.yml - parameters: - legacyCredential: $(dn-bot-dnceng-artifact-feeds-rw) - - template: /eng/common/templates/steps/enable-internal-runtimes.yml + - ${{ if eq(parameters.populateInternalRuntimeVariables, true) }}: + - template: /eng/common/${{ parameters.oneESCompat.templateFolderName }}/steps/enable-internal-sources.yml + parameters: + legacyCredential: $(dn-bot-dnceng-artifact-feeds-rw) + - template: /eng/common/${{ parameters.oneESCompat.templateFolderName }}/steps/enable-internal-runtimes.yml - ${{ if eq(parameters.downloadManifestMsiPackages, true) }}: - task: DownloadBuildArtifacts@1 @@ -84,7 +86,7 @@ jobs: downloadPath: $(Build.SourcesDirectory)/artifacts/downloaded-manifest-msi-packages itemPattern: '**/*Manifest-*.Msi.*.nupkg' checkDownloadedFiles: true - displayName: Download Manifest msi packages + displayName: 🟣 Download Manifest MSI Packages ############### BUILDING ############### - ${{ if eq(parameters.pool.os, 'windows') }}: @@ -105,10 +107,6 @@ jobs: BuildConfig: $(buildConfiguration) TestFullMSBuild: ${{ parameters.testFullMSBuild }} - - ${{ if eq(parameters.targetArchitecture, 'x64') }}: - - powershell: build/RunTestTemplateTests.ps1 - displayName: 🟣 Run Test Templates Tests - - ${{ else }}: - script: | source $(Build.SourcesDirectory)/eng/common/native/init-os-and-arch.sh @@ -141,12 +139,14 @@ jobs: - script: $(Build.SourcesDirectory)/artifacts/bin/redist/$(buildConfiguration)/dotnet/dotnet workload install wasm-tools --skip-manifest-update workingDirectory: $(Build.SourcesDirectory)/artifacts/bin displayName: 🟣 Install wasm-tools Workload + # For the /p:Projects syntax for PowerShell, see: https://github.com/dotnet/msbuild/issues/471#issuecomment-1146466335 - ${{ if eq(parameters.pool.os, 'windows') }}: - powershell: eng/common/build.ps1 -restore -test -ci -prepareMachine -nativeToolsOnMachine -configuration $(buildConfiguration) /p:Projects=\`"${{ replace(parameters.testProjects, ';', '`;') }}\`" + /p:TestRunnerAdditionalArguments="${{ parameters.testRunnerAdditionalArguments }}" /p:TargetArchitecture=${{ parameters.targetArchitecture }} ${{ parameters.runtimeSourceProperties }} /p:CustomHelixTargetQueue=${{ parameters.helixTargetQueue }} @@ -159,6 +159,7 @@ jobs: HelixAccessToken: $(HelixApiAccessToken) RunAoTTests: ${{ parameters.runAoTTests }} TestFullMSBuild: ${{ parameters.testFullMSBuild }} + - ${{ else }}: # For the /p:Projects syntax for Bash, see: https://github.com/dotnet/msbuild/issues/471#issuecomment-1690189034 # The /p:CustomHelixTargetQueue syntax is: @ @@ -167,6 +168,7 @@ jobs: -restore -test -ci -prepareMachine -configuration $(buildConfiguration) '/p:Projects="${{ parameters.testProjects }}"' + /p:TestRunnerAdditionalArguments="${{ parameters.testRunnerAdditionalArguments }}" /p:TargetArchitecture=${{ parameters.targetArchitecture }} /p:TargetRid=${{ parameters.runtimeIdentifier }} ${{ parameters.osProperties }} diff --git a/src/sdk/eng/pipelines/templates/jobs/sdk-job-matrix.yml b/src/sdk/eng/pipelines/templates/jobs/sdk-job-matrix.yml index 8e9000f3c6c..870f20d8f88 100644 --- a/src/sdk/eng/pipelines/templates/jobs/sdk-job-matrix.yml +++ b/src/sdk/eng/pipelines/templates/jobs/sdk-job-matrix.yml @@ -31,7 +31,6 @@ parameters: container: azureLinux30Amd64 helixTargetContainer: $(helixTargetContainerPrefix)ubuntu-24.04-helix-amd64 osProperties: /p:OSName=linux /p:BuildSdkDeb=true - runTests: true # Helix is hanging on this job using the container. See: https://github.com/dotnet/dnceng/issues/6000 disableJob: true - categoryName: TemplateEngine diff --git a/src/sdk/global.json b/src/sdk/global.json index 1b17260e86c..cf8f1c01329 100644 --- a/src/sdk/global.json +++ b/src/sdk/global.json @@ -7,7 +7,7 @@ "errorMessage": "The .NET SDK is not installed or is not configured correctly. Please run ./build to install the correct SDK version locally." }, "tools": { - "dotnet": "10.0.100-rc.1.25420.111", + "dotnet": "10.0.100-rc.1.25451.107", "runtimes": { "dotnet": [ "$(MicrosoftNETCorePlatformsPackageVersion)" @@ -21,8 +21,8 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25460.104", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25460.104", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25467.107", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25467.107", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.WixToolset.Sdk": "5.0.2-dotnet.2737382" diff --git a/src/sdk/sdk.slnx b/src/sdk/sdk.slnx index 0246a040f44..dc0633c42d0 100644 --- a/src/sdk/sdk.slnx +++ b/src/sdk/sdk.slnx @@ -312,6 +312,7 @@ + diff --git a/src/sdk/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets b/src/sdk/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets index 3fdb6703011..a90625e732e 100644 --- a/src/sdk/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets +++ b/src/sdk/src/BlazorWasmSdk/Targets/Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets @@ -88,11 +88,9 @@ Copyright (c) .NET Foundation. All rights reserved. $(ResolvePublishRelatedStaticWebAssetsDependsOn); - _ReplaceFingerprintedBlazorJsForPublish $(ResolveCompressedFilesForPublishDependsOn); - _ReplaceFingerprintedBlazorJsForPublish @@ -159,65 +157,6 @@ Copyright (c) .NET Foundation. All rights reserved. - - - <_BlazorJSFileNames>;@(_BlazorJSFile->'%(FileName)'); - - - <_BlazorJSJSStaticWebAsset Include="@(StaticWebAsset)" Condition="$(_BlazorJSFileNames.Contains(';%(FileName);')) and '%(Extension)' == '.js'" /> - <_BlazorJSPublishCandidate Include="%(_BlazorJSJSStaticWebAsset.RelativeDir)%(_BlazorJSJSStaticWebAsset.FileName).%(_BlazorJSJSStaticWebAsset.Fingerprint)%(_BlazorJSJSStaticWebAsset.Extension)" /> - <_BlazorJSPublishCandidate Remove="@(_BlazorJSPublishCandidate)" Condition="'%(Extension)' == '.map'" /> - <_BlazorJSPublishCandidate> - _framework/$([System.IO.Path]::GetFileNameWithoutExtension('%(Filename)'))%(Extension) - - - - - - - - - - - <_BlazorJSJSStaticWebAssetFullPath>@(_BlazorJSJSStaticWebAsset->'%(FullPath)') - - - <_BlazorJSJSStaticWebAsset Include="@(StaticWebAsset)" Condition="'%(AssetTraitName)' == 'Content-Encoding' and '%(RelatedAsset)' == '$(_BlazorJSJSStaticWebAssetFullPath)'" /> - - - - - - - - - - - - diff --git a/src/sdk/src/BuiltInTools/AspireService/AspireServerService.cs b/src/sdk/src/BuiltInTools/AspireService/AspireServerService.cs index bf2f8f341b8..064de0ee7a5 100644 --- a/src/sdk/src/BuiltInTools/AspireService/AspireServerService.cs +++ b/src/sdk/src/BuiltInTools/AspireService/AspireServerService.cs @@ -123,6 +123,7 @@ public List> GetServerConnectionEnvironment() new(DebugSessionServerCertEnvVar, _certificateEncodedBytes), ]; + /// public ValueTask NotifySessionEndedAsync(string dcpId, string sessionId, int processId, int? exitCode, CancellationToken cancelationToken) => SendNotificationAsync( new SessionTerminatedNotification() @@ -136,6 +137,7 @@ public ValueTask NotifySessionEndedAsync(string dcpId, string sessionId, int pro sessionId, cancelationToken); + /// public ValueTask NotifySessionStartedAsync(string dcpId, string sessionId, int processId, CancellationToken cancelationToken) => SendNotificationAsync( new ProcessRestartedNotification() @@ -148,6 +150,7 @@ public ValueTask NotifySessionStartedAsync(string dcpId, string sessionId, int p sessionId, cancelationToken); + /// public ValueTask NotifyLogMessageAsync(string dcpId, string sessionId, bool isStdErr, string data, CancellationToken cancelationToken) => SendNotificationAsync( new ServiceLogsNotification() @@ -161,23 +164,28 @@ public ValueTask NotifyLogMessageAsync(string dcpId, string sessionId, bool isSt sessionId, cancelationToken); - private async ValueTask SendNotificationAsync(TNotification notification, string dcpId, string sessionId, CancellationToken cancelationToken) + /// + private async ValueTask SendNotificationAsync(TNotification notification, string dcpId, string sessionId, CancellationToken cancellationToken) where TNotification : SessionNotification { try { - Log($"[#{sessionId}] Sending '{notification.NotificationType}'"); + Log($"[#{sessionId}] Sending '{notification.NotificationType}': {notification}"); var jsonSerialized = JsonSerializer.SerializeToUtf8Bytes(notification, JsonSerializerOptions); - await SendMessageAsync(dcpId, jsonSerialized, cancelationToken); - } - catch (Exception e) when (e is not OperationCanceledException && LogAndPropagate(e)) - { - } + var success = await SendMessageAsync(dcpId, jsonSerialized, cancellationToken); - bool LogAndPropagate(Exception e) + if (!success) + { + cancellationToken.ThrowIfCancellationRequested(); + Log($"[#{sessionId}] Failed to send message: Connection not found (dcpId='{dcpId}')."); + } + } + catch (Exception e) when (e is not OperationCanceledException) { - Log($"[#{sessionId}] Sending '{notification.NotificationType}' failed: {e.Message}"); - return false; + if (!cancellationToken.IsCancellationRequested) + { + Log($"[#{sessionId}] Failed to send message: {e.Message}"); + } } } @@ -373,15 +381,13 @@ private async Task WriteResponseTextAsync(HttpResponse response, Exception ex, b } } - private async Task SendMessageAsync(string dcpId, byte[] messageBytes, CancellationToken cancellationToken) + private async ValueTask SendMessageAsync(string dcpId, byte[] messageBytes, CancellationToken cancellationToken) { // Find the connection for the passed in dcpId WebSocketConnection? connection = _socketConnectionManager.GetSocketConnection(dcpId); if (connection is null) { - // Most likely the connection has already gone away - Log($"Send message failure: Connection with the following dcpId was not found {dcpId}"); - return; + return false; } var success = false; @@ -405,6 +411,8 @@ private async Task SendMessageAsync(string dcpId, byte[] messageBytes, Cancellat _webSocketAccess.Release(); } + + return success; } private async ValueTask HandleStopSessionRequestAsync(HttpContext context, string sessionId) diff --git a/src/sdk/src/BuiltInTools/AspireService/Models/SessionChangeNotification.cs b/src/sdk/src/BuiltInTools/AspireService/Models/SessionChangeNotification.cs index 579fe6b4a88..d4213593cf5 100644 --- a/src/sdk/src/BuiltInTools/AspireService/Models/SessionChangeNotification.cs +++ b/src/sdk/src/BuiltInTools/AspireService/Models/SessionChangeNotification.cs @@ -56,6 +56,9 @@ internal sealed class SessionTerminatedNotification : SessionNotification [Required] [JsonPropertyName("exit_code")] public required int? ExitCode { get; init; } + + public override string ToString() + => $"pid={Pid}, exit_code={ExitCode}"; } /// @@ -70,6 +73,9 @@ internal sealed class ProcessRestartedNotification : SessionNotification [Required] [JsonPropertyName("pid")] public required int PID { get; init; } + + public override string ToString() + => $"pid={PID}"; } /// @@ -91,4 +97,7 @@ internal sealed class ServiceLogsNotification : SessionNotification [Required] [JsonPropertyName("log_message")] public required string LogMessage { get; init; } + + public override string ToString() + => $"log_message='{LogMessage}', is_std_err={IsStdErr}"; } diff --git a/src/sdk/src/BuiltInTools/DotNetDeltaApplier/StartupHook.cs b/src/sdk/src/BuiltInTools/DotNetDeltaApplier/StartupHook.cs index f9ac8e3463f..28890852482 100644 --- a/src/sdk/src/BuiltInTools/DotNetDeltaApplier/StartupHook.cs +++ b/src/sdk/src/BuiltInTools/DotNetDeltaApplier/StartupHook.cs @@ -89,7 +89,7 @@ private static void Log(string message) if (!string.IsNullOrEmpty(prefix)) { Console.ForegroundColor = ConsoleColor.DarkGray; - Console.WriteLine($"{prefix} {message}"); + Console.Error.WriteLine($"{prefix} {message}"); Console.ResetColor(); } } diff --git a/src/sdk/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs b/src/sdk/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs index 7587b762311..1063ba1635f 100644 --- a/src/sdk/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs +++ b/src/sdk/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs @@ -35,9 +35,14 @@ public override void Dispose() private void DisposePipe() { - Logger.LogDebug("Disposing agent communication pipe"); - _pipe?.Dispose(); - _pipe = null; + if (_pipe != null) + { + Logger.LogDebug("Disposing agent communication pipe"); + + // Dispose the pipe but do not set it to null, so that any in-progress + // operations throw the appropriate exception type. + _pipe.Dispose(); + } } // for testing @@ -101,8 +106,7 @@ private void RequireReadyForUpdates() // should only be called after connection has been created: _ = GetCapabilitiesTask(); - if (_pipe == null) - throw new InvalidOperationException("Pipe has been disposed."); + Debug.Assert(_pipe != null); } public override void ConfigureLaunchEnvironment(IDictionary environmentBuilder) @@ -152,7 +156,13 @@ public override async Task ApplyManagedCodeUpdatesAsync(ImmutableAr { if (!success) { - Logger.LogWarning("Further changes won't be applied to this process."); + // Don't report a warning when cancelled. The process has terminated or the host is shutting down in that case. + // Best effort: There is an inherent race condition due to time between the process exiting and the cancellation token triggering. + if (!cancellationToken.IsCancellationRequested) + { + Logger.LogWarning("Further changes won't be applied to this process."); + } + _managedCodeUpdateFailedOrCancelled = true; DisposePipe(); } @@ -216,7 +226,7 @@ public async override Task ApplyStaticAssetUpdatesAsync(ImmutableAr private ValueTask SendAndReceiveUpdateAsync(TRequest request, bool isProcessSuspended, CancellationToken cancellationToken) where TRequest : IUpdateRequest { - // Should not be disposed: + // Should not initialized: Debug.Assert(_pipe != null); return SendAndReceiveUpdateAsync( @@ -241,8 +251,10 @@ async ValueTask SendAndReceiveAsync(int batchId, CancellationToken cancell Logger.LogDebug("Update batch #{UpdateId} failed.", batchId); } - catch (Exception e) when (e is not OperationCanceledException || isProcessSuspended) + catch (Exception e) { + // Don't report an error when cancelled. The process has terminated or the host is shutting down in that case. + // Best effort: There is an inherent race condition due to time between the process exiting and the cancellation token triggering. if (cancellationToken.IsCancellationRequested) { Logger.LogDebug("Update batch #{UpdateId} canceled.", batchId); @@ -267,7 +279,7 @@ async ValueTask WriteRequestAsync(CancellationToken cancellationToken) private async ValueTask ReceiveUpdateResponseAsync(CancellationToken cancellationToken) { - // Should not be disposed: + // Should be initialized: Debug.Assert(_pipe != null); var (success, log) = await UpdateResponse.ReadAsync(_pipe, cancellationToken); @@ -296,10 +308,12 @@ public override async Task InitialUpdatesAppliedAsync(CancellationToken cancella } catch (Exception e) when (e is not OperationCanceledException) { - // pipe might throw another exception when forcibly closed on process termination: + // Pipe might throw another exception when forcibly closed on process termination. + // Don't report an error when cancelled. The process has terminated or the host is shutting down in that case. + // Best effort: There is an inherent race condition due to time between the process exiting and the cancellation token triggering. if (!cancellationToken.IsCancellationRequested) { - Logger.LogError("Failed to send InitialUpdatesCompleted: {Message}", e.Message); + Logger.LogError("Failed to send {RequestType}: {Message}", nameof(RequestType.InitialUpdatesCompleted), e.Message); } } } diff --git a/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClient.cs b/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClient.cs index fe14176a8b6..e5efa4db2a7 100644 --- a/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClient.cs +++ b/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClient.cs @@ -41,23 +41,42 @@ internal Task PendingUpdates /// /// Initiates connection with the agent in the target process. /// + /// Cancellation token. The cancellation should trigger on process terminatation. public abstract void InitiateConnection(CancellationToken cancellationToken); /// /// Waits until the connection with the agent is established. /// + /// Cancellation token. The cancellation should trigger on process terminatation. public abstract Task WaitForConnectionEstablishedAsync(CancellationToken cancellationToken); + /// + /// Returns update capabilities of the target process. + /// + /// Cancellation token. The cancellation should trigger on process terminatation. public abstract Task> GetUpdateCapabilitiesAsync(CancellationToken cancellationToken); + /// + /// Applies managed code updates to the target process. + /// + /// Cancellation token. The cancellation should trigger on process terminatation. public abstract Task ApplyManagedCodeUpdatesAsync(ImmutableArray updates, bool isProcessSuspended, CancellationToken cancellationToken); + + /// + /// Applies static asset updates to the target process. + /// + /// Cancellation token. The cancellation should trigger on process terminatation. public abstract Task ApplyStaticAssetUpdatesAsync(ImmutableArray updates, bool isProcessSuspended, CancellationToken cancellationToken); /// /// Notifies the agent that the initial set of updates has been applied and the user code in the process can start executing. /// + /// Cancellation token. The cancellation should trigger on process terminatation. public abstract Task InitialUpdatesAppliedAsync(CancellationToken cancellationToken); + /// + /// Disposes the client. Can occur unexpectedly whenever the process exits. + /// public abstract void Dispose(); public static void ReportLogEntry(ILogger logger, string message, AgentMessageSeverity severity) @@ -72,7 +91,7 @@ public static void ReportLogEntry(ILogger logger, string message, AgentMessageSe logger.Log(level, message); } - public async Task> FilterApplicableUpdatesAsync(ImmutableArray updates, CancellationToken cancellationToken) + protected async Task> FilterApplicableUpdatesAsync(ImmutableArray updates, CancellationToken cancellationToken) { var availableCapabilities = await GetUpdateCapabilitiesAsync(cancellationToken); var applicableUpdates = new List(); diff --git a/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClients.cs b/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClients.cs index bd0a4be6799..58676fdcf5d 100644 --- a/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClients.cs +++ b/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClients.cs @@ -23,6 +23,9 @@ public HotReloadClients(HotReloadClient client, AbstractBrowserRefreshServer? br { } + /// + /// Disposes all clients. Can occur unexpectedly whenever the process exits. + /// public void Dispose() { foreach (var (client, _) in clients) @@ -56,6 +59,7 @@ internal void ConfigureLaunchEnvironment(IDictionary environment browserRefreshServer?.ConfigureLaunchEnvironment(environmentBuilder, enableHotReload: true); } + /// Cancellation token. The cancellation should trigger on process terminatation. internal void InitiateConnection(CancellationToken cancellationToken) { foreach (var (client, _) in clients) @@ -64,11 +68,13 @@ internal void InitiateConnection(CancellationToken cancellationToken) } } + /// Cancellation token. The cancellation should trigger on process terminatation. internal async ValueTask WaitForConnectionEstablishedAsync(CancellationToken cancellationToken) { await Task.WhenAll(clients.Select(c => c.client.WaitForConnectionEstablishedAsync(cancellationToken))); } + /// Cancellation token. The cancellation should trigger on process terminatation. public async ValueTask> GetUpdateCapabilitiesAsync(CancellationToken cancellationToken) { if (clients is [var (singleClient, _)]) @@ -83,6 +89,7 @@ public async ValueTask> GetUpdateCapabilitiesAsync(Cancel return [.. results.SelectMany(r => r).Distinct(StringComparer.Ordinal).OrderBy(c => c)]; } + /// Cancellation token. The cancellation should trigger on process terminatation. public async ValueTask ApplyManagedCodeUpdatesAsync(ImmutableArray updates, bool isProcessSuspended, CancellationToken cancellationToken) { var anyFailure = false; @@ -139,6 +146,7 @@ public async ValueTask ApplyManagedCodeUpdatesAsync(ImmutableArrayCancellation token. The cancellation should trigger on process terminatation. public async ValueTask InitialUpdatesAppliedAsync(CancellationToken cancellationToken) { if (clients is [var (singleClient, _)]) @@ -151,6 +159,7 @@ public async ValueTask InitialUpdatesAppliedAsync(CancellationToken cancellation } } + /// Cancellation token. The cancellation should trigger on process terminatation. public async Task ApplyStaticAssetUpdatesAsync(IEnumerable<(string filePath, string relativeUrl, string assemblyName, bool isApplicationProject)> assets, CancellationToken cancellationToken) { if (browserRefreshServer != null) @@ -173,7 +182,7 @@ public async Task ApplyStaticAssetUpdatesAsync(IEnumerable<(string filePath, str #endif content = ImmutableCollectionsMarshal.AsImmutableArray(blob); } - catch (Exception e) + catch (Exception e) when (e is not OperationCanceledException) { ClientLogger.LogError("Failed to read file {FilePath}: {Message}", filePath, e.Message); continue; @@ -190,6 +199,7 @@ public async Task ApplyStaticAssetUpdatesAsync(IEnumerable<(string filePath, str } } + /// Cancellation token. The cancellation should trigger on process terminatation. public async ValueTask ApplyStaticAssetUpdatesAsync(ImmutableArray updates, bool isProcessSuspended, CancellationToken cancellationToken) { if (clients is [var (singleClient, _)]) @@ -202,6 +212,7 @@ public async ValueTask ApplyStaticAssetUpdatesAsync(ImmutableArrayCancellation token. The cancellation should trigger on process terminatation. public ValueTask ReportCompilationErrorsInApplicationAsync(ImmutableArray compilationErrors, CancellationToken cancellationToken) => browserRefreshServer?.ReportCompilationErrorsInBrowserAsync(compilationErrors, cancellationToken) ?? ValueTask.CompletedTask; } diff --git a/src/sdk/src/BuiltInTools/HotReloadClient/Logging/LogEvents.cs b/src/sdk/src/BuiltInTools/HotReloadClient/Logging/LogEvents.cs index a74e5097a6d..7be92781e01 100644 --- a/src/sdk/src/BuiltInTools/HotReloadClient/Logging/LogEvents.cs +++ b/src/sdk/src/BuiltInTools/HotReloadClient/Logging/LogEvents.cs @@ -25,9 +25,11 @@ public static void Log(this ILogger logger, LogEvent logEvent, params object[] a public static readonly LogEvent HotReloadSucceeded = Create(LogLevel.Information, "Hot reload succeeded."); public static readonly LogEvent RefreshingBrowser = Create(LogLevel.Debug, "Refreshing browser."); public static readonly LogEvent ReloadingBrowser = Create(LogLevel.Debug, "Reloading browser."); + public static readonly LogEvent SendingWaitMessage = Create(LogLevel.Debug, "Sending wait message."); public static readonly LogEvent NoBrowserConnected = Create(LogLevel.Debug, "No browser is connected."); public static readonly LogEvent FailedToReceiveResponseFromConnectedBrowser = Create(LogLevel.Debug, "Failed to receive response from a connected browser."); public static readonly LogEvent UpdatingDiagnostics = Create(LogLevel.Debug, "Updating diagnostics."); public static readonly LogEvent SendingStaticAssetUpdateRequest = Create(LogLevel.Debug, "Sending static asset update request to connected browsers: '{0}'."); public static readonly LogEvent RefreshServerRunningAt = Create(LogLevel.Debug, "Refresh server running at {0}."); + public static readonly LogEvent ConnectedToRefreshServer = Create(LogLevel.Debug, "Connected to refresh server."); } diff --git a/src/sdk/src/BuiltInTools/HotReloadClient/Web/AbstractBrowserRefreshServer.cs b/src/sdk/src/BuiltInTools/HotReloadClient/Web/AbstractBrowserRefreshServer.cs index eda15d200f9..91d99296db0 100644 --- a/src/sdk/src/BuiltInTools/HotReloadClient/Web/AbstractBrowserRefreshServer.cs +++ b/src/sdk/src/BuiltInTools/HotReloadClient/Web/AbstractBrowserRefreshServer.cs @@ -101,7 +101,7 @@ public void ConfigureLaunchEnvironment(IDictionary builder, bool builder[MiddlewareEnvironmentVariables.DotNetModifiableAssemblies] = "debug"; } - if (logger.IsEnabled(LogLevel.Debug)) + if (logger.IsEnabled(LogLevel.Trace)) { // enable debug logging from middleware: builder[MiddlewareEnvironmentVariables.LoggingLevel] = "Debug"; @@ -163,7 +163,7 @@ public async Task WaitForClientConnectionAsync(CancellationToken cancellationTok }, progressCancellationSource.Token); // Work around lack of Task.WaitAsync(cancellationToken) on .NET Framework: - cancellationToken.Register(() => _browserConnected.SetCanceled()); + cancellationToken.Register(() => _browserConnected.TrySetCanceled()); try { @@ -237,8 +237,12 @@ public ValueTask SendReloadMessageAsync(CancellationToken cancellationToken) } public ValueTask SendWaitMessageAsync(CancellationToken cancellationToken) - => SendAsync(s_waitMessage, cancellationToken); + { + logger.Log(LogEvents.SendingWaitMessage); + return SendAsync(s_waitMessage, cancellationToken); + } + // obsolete: to be removed public ValueTask SendPingMessageAsync(CancellationToken cancellationToken) => SendAsync(s_pingMessage, cancellationToken); diff --git a/src/sdk/src/BuiltInTools/HotReloadClient/Web/BrowserConnection.cs b/src/sdk/src/BuiltInTools/HotReloadClient/Web/BrowserConnection.cs index 507595eb89d..498c2611008 100644 --- a/src/sdk/src/BuiltInTools/HotReloadClient/Web/BrowserConnection.cs +++ b/src/sdk/src/BuiltInTools/HotReloadClient/Web/BrowserConnection.cs @@ -37,7 +37,7 @@ public BrowserConnection(WebSocket clientSocket, string? sharedSecret, ILoggerFa ServerLogger = loggerFactory.CreateLogger(ServerLogComponentName, displayName); AgentLogger = loggerFactory.CreateLogger(AgentLogComponentName, displayName); - ServerLogger.LogDebug("Connected to referesh server."); + ServerLogger.Log(LogEvents.ConnectedToRefreshServer); } public void Dispose() diff --git a/src/sdk/src/BuiltInTools/dotnet-format/Formatters/CharsetFormatter.cs b/src/sdk/src/BuiltInTools/dotnet-format/Formatters/CharsetFormatter.cs index b2aa5af5184..5e8d9ee6cfa 100644 --- a/src/sdk/src/BuiltInTools/dotnet-format/Formatters/CharsetFormatter.cs +++ b/src/sdk/src/BuiltInTools/dotnet-format/Formatters/CharsetFormatter.cs @@ -68,7 +68,8 @@ private static byte[] GetEncodedBytes(string text, Encoding encoding) private static bool TryGetCharset(AnalyzerConfigOptions analyzerConfigOptions, [NotNullWhen(true)] out Encoding? encoding) { if (analyzerConfigOptions != null && - analyzerConfigOptions.TryGetValue("charset", out var charsetOption)) + analyzerConfigOptions.TryGetValue("charset", out var charsetOption) && + charsetOption != "unset") { encoding = GetCharset(charsetOption); return true; diff --git a/src/sdk/src/BuiltInTools/dotnet-watch.slnf b/src/sdk/src/BuiltInTools/dotnet-watch.slnf index 09d529c61e9..b7454eb8869 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch.slnf +++ b/src/sdk/src/BuiltInTools/dotnet-watch.slnf @@ -18,10 +18,11 @@ "src\\BuiltInTools\\HotReloadClient\\Microsoft.DotNet.HotReload.Client.shproj", "src\\BuiltInTools\\dotnet-watch\\dotnet-watch.csproj", "test\\Microsoft.AspNetCore.Watch.BrowserRefresh.Tests\\Microsoft.AspNetCore.Watch.BrowserRefresh.Tests.csproj", + "test\\Microsoft.DotNet.HotReload.Client.Tests\\Microsoft.DotNet.HotReload.Client.Tests.csproj", "test\\Microsoft.Extensions.DotNetDeltaApplier.Tests\\Microsoft.Extensions.DotNetDeltaApplier.Tests.csproj", "test\\Microsoft.NET.TestFramework\\Microsoft.NET.TestFramework.csproj", "test\\Microsoft.WebTools.AspireService.Tests\\Microsoft.WebTools.AspireService.Tests.csproj", - "test\\Microsoft.DotNet.HotReload.Client.Tests\\Microsoft.DotNet.HotReload.Client.Tests.csproj", + "test\\dotnet-watch-test-browser\\dotnet-watch-test-browser.csproj", "test\\dotnet-watch.Tests\\dotnet-watch.Tests.csproj" ] } diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/Aspire/AspireServiceFactory.cs b/src/sdk/src/BuiltInTools/dotnet-watch/Aspire/AspireServiceFactory.cs index 1e84fb05a40..3942cb4e2ea 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/Aspire/AspireServiceFactory.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/Aspire/AspireServiceFactory.cs @@ -43,6 +43,7 @@ private readonly struct Session(string dcpId, string sessionId, RunningProject r private readonly Dictionary _sessions = []; private int _sessionIdDispenser; + private volatile bool _isDisposed; public SessionManager(ProjectLauncher projectLauncher, ProjectOptions hostProjectOptions) @@ -82,10 +83,7 @@ public async ValueTask TerminateLaunchedProcessesAsync(CancellationToken cancell _sessions.Clear(); } - foreach (var session in sessions) - { - await TerminateSessionAsync(session, cancellationToken); - } + await Task.WhenAll(sessions.Select(TerminateSessionAsync)).WaitAsync(cancellationToken); } public IEnumerable<(string name, string value)> GetEnvironmentVariables() @@ -113,7 +111,9 @@ public async ValueTask StartProjectAsync(string dcpId, string se var processTerminationSource = new CancellationTokenSource(); var outputChannel = Channel.CreateUnbounded(s_outputChannelOptions); - var runningProject = await _projectLauncher.TryLaunchProcessAsync( + RunningProject? runningProject = null; + + runningProject = await _projectLauncher.TryLaunchProcessAsync( projectOptions, processTerminationSource, onOutput: line => @@ -121,6 +121,21 @@ public async ValueTask StartProjectAsync(string dcpId, string se var writeResult = outputChannel.Writer.TryWrite(line); Debug.Assert(writeResult); }, + onExit: async (processId, exitCode) => + { + // Project can be null if the process exists while it's being initialized. + if (runningProject?.IsRestarting == false) + { + try + { + await _service.NotifySessionEndedAsync(dcpId, sessionId, processId, exitCode, cancellationToken); + } + catch (OperationCanceledException) + { + // canceled on shutdown, ignore + } + } + }, restartOperation: cancellationToken => StartProjectAsync(dcpId, sessionId, projectOptions, isRestart: true, cancellationToken), cancellationToken); @@ -134,7 +149,7 @@ public async ValueTask StartProjectAsync(string dcpId, string se await _service.NotifySessionStartedAsync(dcpId, sessionId, runningProject.ProcessId, cancellationToken); // cancel reading output when the process terminates: - var outputReader = StartChannelReader(processTerminationSource.Token); + var outputReader = StartChannelReader(runningProject.ProcessExitedCancellationToken); lock (_guard) { @@ -159,7 +174,7 @@ async Task StartChannelReader(CancellationToken cancellationToken) } catch (Exception e) { - if (e is not OperationCanceledException) + if (!cancellationToken.IsCancellationRequested) { _logger.LogError("Unexpected error reading output of session '{SessionId}': {Exception}", sessionId, e); } @@ -185,18 +200,15 @@ async ValueTask IAspireServerEvents.StopSessionAsync(string dcpId, string _sessions.Remove(sessionId); } - await TerminateSessionAsync(session, cancellationToken); + await TerminateSessionAsync(session); return true; } - private async ValueTask TerminateSessionAsync(Session session, CancellationToken cancellationToken) + private async Task TerminateSessionAsync(Session session) { _logger.LogDebug("Stop session #{SessionId}", session.Id); - var exitCode = await _projectLauncher.TerminateProcessAsync(session.RunningProject, cancellationToken); - - // Wait until the started notification has been sent so that we don't send out of order notifications: - await _service.NotifySessionEndedAsync(session.DcpId, session.Id, session.RunningProject.ProcessId, exitCode, cancellationToken); + await session.RunningProject.TerminateAsync(isRestarting: false); // process termination should cancel output reader task: await session.OutputReader; diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/Browser/BrowserLauncher.cs b/src/sdk/src/BuiltInTools/dotnet-watch/Browser/BrowserLauncher.cs index 1c345803c21..c841191e020 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/Browser/BrowserLauncher.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/Browser/BrowserLauncher.cs @@ -4,13 +4,14 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Microsoft.Build.Graph; using Microsoft.DotNet.HotReload; using Microsoft.Extensions.Logging; namespace Microsoft.DotNet.Watch; -internal sealed class BrowserLauncher(ILogger logger, EnvironmentOptions environmentOptions) +internal sealed class BrowserLauncher(ILogger logger, IProcessOutputReporter processOutputReporter, EnvironmentOptions environmentOptions) { // interlocked private ImmutableHashSet _browserLaunchAttempted = []; @@ -61,18 +62,13 @@ public static string GetLaunchUrl(string? profileLaunchUrl, string outputLaunchU private void LaunchBrowser(string launchUrl, AbstractBrowserRefreshServer? server) { - var fileName = launchUrl; + var (fileName, arg, useShellExecute) = environmentOptions.BrowserPath is { } browserPath + ? (browserPath, launchUrl, false) + : (launchUrl, null, true); - var args = string.Empty; - if (environmentOptions.BrowserPath is { } browserPath) - { - args = fileName; - fileName = browserPath; - } + logger.Log(MessageDescriptor.LaunchingBrowser, fileName, arg); - logger.LogDebug("Launching browser: {FileName} {Args}", fileName, args); - - if (environmentOptions.TestFlags != TestFlags.None) + if (environmentOptions.TestFlags != TestFlags.None && environmentOptions.BrowserPath == null) { if (environmentOptions.TestFlags.HasFlag(TestFlags.MockBrowser)) { @@ -83,29 +79,23 @@ private void LaunchBrowser(string launchUrl, AbstractBrowserRefreshServer? serve return; } - var info = new ProcessStartInfo + // dotnet-watch, by default, relies on URL file association to launch browsers. On Windows and MacOS, this works fairly well + // where URLs are associated with the default browser. On Linux, this is a bit murky. + // From emperical observation, it's noted that failing to launch a browser results in either Process.Start returning a null-value + // or for the process to have immediately exited. + // We can use this to provide a helpful message. + var processSpec = new ProcessSpec() { - FileName = fileName, - Arguments = args, - UseShellExecute = true, + Executable = fileName, + Arguments = arg != null ? [arg] : [], + UseShellExecute = useShellExecute, + OnOutput = environmentOptions.TestFlags.HasFlag(TestFlags.RedirectBrowserOutput) ? processOutputReporter.ReportOutput : null, }; - try - { - using var browserProcess = Process.Start(info); - if (browserProcess is null or { HasExited: true }) - { - // dotnet-watch, by default, relies on URL file association to launch browsers. On Windows and MacOS, this works fairly well - // where URLs are associated with the default browser. On Linux, this is a bit murky. - // From emperical observation, it's noted that failing to launch a browser results in either Process.Start returning a null-value - // or for the process to have immediately exited. - // We can use this to provide a helpful message. - logger.LogInformation("Unable to launch the browser. Url '{Url}'.", launchUrl); - } - } - catch (Exception e) + using var browserProcess = ProcessRunner.TryStartProcess(processSpec, logger); + if (browserProcess is null or { HasExited: true }) { - logger.LogDebug("Failed to launch a browser: {Message}", e.Message); + logger.LogWarning("Unable to launch the browser. Url '{Url}'.", launchUrl); } } diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/Build/ProjectGraphUtilities.cs b/src/sdk/src/BuiltInTools/dotnet-watch/Build/ProjectGraphUtilities.cs index ca8f616ebcc..56bcba3427e 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/Build/ProjectGraphUtilities.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/Build/ProjectGraphUtilities.cs @@ -43,6 +43,10 @@ internal static class ProjectGraphUtilities } catch (Exception e) when (e is not OperationCanceledException) { + // ProejctGraph aggregates OperationCanceledException exception, + // throw here to propagate the cancellation. + cancellationToken.ThrowIfCancellationRequested(); + logger.LogDebug("Failed to load project graph."); if (e is AggregateException { InnerExceptions: var innerExceptions }) diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/CommandLine/EnvironmentOptions.cs b/src/sdk/src/BuiltInTools/dotnet-watch/CommandLine/EnvironmentOptions.cs index f2fbfa7cabd..72f78733253 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/CommandLine/EnvironmentOptions.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/CommandLine/EnvironmentOptions.cs @@ -22,6 +22,11 @@ internal enum TestFlags /// This allows tests to trigger key based events. /// ReadKeyFromStdin = 1 << 3, + + /// + /// Redirects the output of the launched browser process to watch output. + /// + RedirectBrowserOutput = 1 << 4, } internal sealed record EnvironmentOptions( diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs b/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs index cedccb2351f..55aea79f0d1 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs @@ -15,7 +15,6 @@ namespace Microsoft.DotNet.Watch internal sealed class CompilationHandler : IDisposable { public readonly IncrementalMSBuildWorkspace Workspace; - private readonly ILoggerFactory _loggerFactory; private readonly ILogger _logger; private readonly WatchHotReloadService _hotReloadService; private readonly ProcessRunner _processRunner; @@ -40,9 +39,8 @@ internal sealed class CompilationHandler : IDisposable private bool _isDisposed; - public CompilationHandler(ILoggerFactory loggerFactory, ILogger logger, ProcessRunner processRunner) + public CompilationHandler(ILogger logger, ProcessRunner processRunner) { - _loggerFactory = loggerFactory; _logger = logger; _processRunner = processRunner; Workspace = new IncrementalMSBuildWorkspace(logger); @@ -57,15 +55,8 @@ public void Dispose() public async ValueTask TerminateNonRootProcessesAndDispose(CancellationToken cancellationToken) { - _logger.LogDebug("Disposing remaining child processes."); - - var projectsToDispose = await TerminateNonRootProcessesAsync(projectPaths: null, cancellationToken); - - foreach (var project in projectsToDispose) - { - project.Dispose(); - } - + _logger.LogDebug("Terminating remaining child processes."); + await TerminateNonRootProcessesAsync(projectPaths: null, cancellationToken); Dispose(); } @@ -101,19 +92,35 @@ public async ValueTask StartSessionAsync(CancellationToken cancellationToken) CancellationToken cancellationToken) { var processExitedSource = new CancellationTokenSource(); - var processCommunicationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(processExitedSource.Token, cancellationToken); + + // Cancel process communication as soon as process termination is requested, shutdown is requested, or the process exits (whichever comes first). + // If we only cancel after we process exit event handler is triggered the pipe might have already been closed and may fail unexpectedly. + using var processCommunicationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(processTerminationSource.Token, processExitedSource.Token, cancellationToken); + var processCommunicationCancellationToken = processCommunicationCancellationSource.Token; // Dispose these objects on failure: - using var disposables = new Disposables([clients, processExitedSource, processCommunicationCancellationSource]); + using var disposables = new Disposables([clients, processExitedSource]); // It is important to first create the named pipe connection (Hot Reload client is the named pipe server) // and then start the process (named pipe client). Otherwise, the connection would fail. - clients.InitiateConnection(processCommunicationCancellationSource.Token); + clients.InitiateConnection(processCommunicationCancellationToken); - processSpec.OnExit += (_, _) => + RunningProject? publishedRunningProject = null; + + var previousOnExit = processSpec.OnExit; + processSpec.OnExit = async (processId, exitCode) => { - processExitedSource.Cancel(); - return ValueTask.CompletedTask; + // Await the previous action so that we only clean up after all requested "on exit" actions have been completed. + if (previousOnExit != null) + { + await previousOnExit(processId, exitCode); + } + + // Remove the running project if it has been published to _runningProjects (if it hasn't exited during initialization): + if (publishedRunningProject != null && RemoveRunningProject(publishedRunningProject)) + { + publishedRunningProject.Dispose(); + } }; var launchResult = new ProcessLaunchResult(); @@ -124,79 +131,88 @@ public async ValueTask StartSessionAsync(CancellationToken cancellationToken) return null; } - // Wait for agent to create the name pipe and send capabilities over. - // the agent blocks the app execution until initial updates are applied (if any). - var capabilities = await clients.GetUpdateCapabilitiesAsync(processCommunicationCancellationSource.Token); - - var runningProject = new RunningProject( - projectNode, - projectOptions, - clients, - runningProcess, - launchResult.ProcessId.Value, - processExitedSource: processExitedSource, - processTerminationSource: processTerminationSource, - restartOperation: restartOperation, - disposables: [processCommunicationCancellationSource], - capabilities); - var projectPath = projectNode.ProjectInstance.FullPath; - // ownership transferred to running project: - disposables.Items.Clear(); - disposables.Items.Add(runningProject); - - var appliedUpdateCount = 0; - while (true) + try { - // Observe updates that need to be applied to the new process - // and apply them before adding it to running processes. - // Do not block on udpates being made to other processes to avoid delaying the new process being up-to-date. - var updatesToApply = _previousUpdates.Skip(appliedUpdateCount).ToImmutableArray(); - if (updatesToApply.Any()) + // Wait for agent to create the name pipe and send capabilities over. + // the agent blocks the app execution until initial updates are applied (if any). + var capabilities = await clients.GetUpdateCapabilitiesAsync(processCommunicationCancellationToken); + + var runningProject = new RunningProject( + projectNode, + projectOptions, + clients, + runningProcess, + launchResult.ProcessId.Value, + processExitedSource: processExitedSource, + processTerminationSource: processTerminationSource, + restartOperation: restartOperation, + capabilities); + + // ownership transferred to running project: + disposables.Items.Clear(); + disposables.Items.Add(runningProject); + + var appliedUpdateCount = 0; + while (true) { - await clients.ApplyManagedCodeUpdatesAsync(ToManagedCodeUpdates(updatesToApply), isProcessSuspended: false, processCommunicationCancellationSource.Token); - } - - appliedUpdateCount += updatesToApply.Length; - - lock (_runningProjectsAndUpdatesGuard) - { - ObjectDisposedException.ThrowIf(_isDisposed, this); - - // More updates might have come in while we have been applying updates. - // If so, continue updating. - if (_previousUpdates.Count > appliedUpdateCount) + // Observe updates that need to be applied to the new process + // and apply them before adding it to running processes. + // Do not block on udpates being made to other processes to avoid delaying the new process being up-to-date. + var updatesToApply = _previousUpdates.Skip(appliedUpdateCount).ToImmutableArray(); + if (updatesToApply.Any()) { - continue; + await clients.ApplyManagedCodeUpdatesAsync(ToManagedCodeUpdates(updatesToApply), isProcessSuspended: false, processCommunicationCancellationToken); } - // Only add the running process after it has been up-to-date. - // This will prevent new updates being applied before we have applied all the previous updates. - if (!_runningProjects.TryGetValue(projectPath, out var projectInstances)) + appliedUpdateCount += updatesToApply.Length; + + lock (_runningProjectsAndUpdatesGuard) { - projectInstances = []; - } + ObjectDisposedException.ThrowIf(_isDisposed, this); - _runningProjects = _runningProjects.SetItem(projectPath, projectInstances.Add(runningProject)); + // More updates might have come in while we have been applying updates. + // If so, continue updating. + if (_previousUpdates.Count > appliedUpdateCount) + { + continue; + } - // ownership transferred to _runningProjects - disposables.Items.Clear(); - break; + // Only add the running process after it has been up-to-date. + // This will prevent new updates being applied before we have applied all the previous updates. + if (!_runningProjects.TryGetValue(projectPath, out var projectInstances)) + { + projectInstances = []; + } + + _runningProjects = _runningProjects.SetItem(projectPath, projectInstances.Add(runningProject)); + + // ownership transferred to _runningProjects + publishedRunningProject = runningProject; + disposables.Items.Clear(); + break; + } } - } - // Notifies the agent that it can unblock the execution of the process: - await clients.InitialUpdatesAppliedAsync(cancellationToken); + // Notifies the agent that it can unblock the execution of the process: + await clients.InitialUpdatesAppliedAsync(processCommunicationCancellationToken); - // If non-empty solution is loaded into the workspace (a Hot Reload session is active): - if (Workspace.CurrentSolution is { ProjectIds: not [] } currentSolution) + // If non-empty solution is loaded into the workspace (a Hot Reload session is active): + if (Workspace.CurrentSolution is { ProjectIds: not [] } currentSolution) + { + // Preparing the compilation is a perf optimization. We can skip it if the session hasn't been started yet. + PrepareCompilations(currentSolution, projectPath, cancellationToken); + } + + return runningProject; + } + catch (OperationCanceledException) when (processExitedSource.IsCancellationRequested) { - // Preparing the compilation is a perf optimization. We can skip it if the session hasn't been started yet. - PrepareCompilations(currentSolution, projectPath, cancellationToken); + // Process exited during initialization. This should not happen since we control the process during this time. + _logger.LogError("Failed to launch '{ProjectPath}'. Process {PID} exited during initialization.", projectPath, launchResult.ProcessId); + return null; } - - return runningProject; } private ImmutableArray GetAggregateCapabilities() @@ -229,7 +245,7 @@ private static void PrepareCompilations(Solution solution, string projectPath, C ImmutableArray projectUpdates, ImmutableArray projectsToRebuild, ImmutableArray projectsToRedeploy, - ImmutableArray terminatedProjects)> HandleManagedCodeChangesAsync( + ImmutableArray projectsToRestart)> HandleManagedCodeChangesAsync( bool autoRestart, Func, CancellationToken, Task> restartPrompt, CancellationToken cancellationToken) @@ -284,11 +300,11 @@ private static void PrepareCompilations(Solution solution, string projectPath, C // Terminate all tracked processes that need to be restarted, // except for the root process, which will terminate later on. - var terminatedProjects = updates.ProjectsToRestart.IsEmpty + var projectsToRestart = updates.ProjectsToRestart.IsEmpty ? [] : await TerminateNonRootProcessesAsync(updates.ProjectsToRestart.Select(e => currentSolution.GetProject(e.Key)!.FilePath!), cancellationToken); - return (updates.ProjectUpdates, projectsToRebuild, projectsToRedeploy, terminatedProjects); + return (updates.ProjectUpdates, projectsToRebuild, projectsToRedeploy, projectsToRestart); } public async ValueTask ApplyUpdatesAsync(ImmutableArray updates, CancellationToken cancellationToken) @@ -312,10 +328,10 @@ await ForEachProjectAsync(projectsToUpdate, async (runningProject, cancellationT { try { - using var processCommunicationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(runningProject.ProcessExitedSource.Token, cancellationToken); + using var processCommunicationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(runningProject.ProcessExitedCancellationToken, cancellationToken); await runningProject.Clients.ApplyManagedCodeUpdatesAsync(ToManagedCodeUpdates(updates), isProcessSuspended: false, processCommunicationCancellationSource.Token); } - catch (OperationCanceledException) when (runningProject.ProcessExitedSource.Token.IsCancellationRequested && !cancellationToken.IsCancellationRequested) + catch (OperationCanceledException) when (runningProject.ProcessExitedCancellationToken.IsCancellationRequested && !cancellationToken.IsCancellationRequested) { runningProject.Clients.ClientLogger.Log(MessageDescriptor.HotReloadCanceledProcessExited); } @@ -363,7 +379,7 @@ private async ValueTask DisplayResultsAsync(WatchHotReloadService.Updates2 updat _logger.Log(MessageDescriptor.RestartNeededToApplyChanges); } - var diagnosticsToDisplayInApp = new List(); + var errorsToDisplayInApp = new List(); // Display errors first, then warnings: ReportCompilationDiagnostics(DiagnosticSeverity.Error); @@ -373,7 +389,7 @@ private async ValueTask DisplayResultsAsync(WatchHotReloadService.Updates2 updat // report or clear diagnostics in the browser UI await ForEachProjectAsync( _runningProjects, - (project, cancellationToken) => project.Clients.ReportCompilationErrorsInApplicationAsync([.. diagnosticsToDisplayInApp], cancellationToken).AsTask() ?? Task.CompletedTask, + (project, cancellationToken) => project.Clients.ReportCompilationErrorsInApplicationAsync([.. errorsToDisplayInApp], cancellationToken).AsTask() ?? Task.CompletedTask, cancellationToken); void ReportCompilationDiagnostics(DiagnosticSeverity severity) @@ -437,16 +453,20 @@ void ReportRudeEdits() bool IsAutoRestartEnabled(ProjectId id) => runningProjectInfos.TryGetValue(id, out var info) && info.RestartWhenChangesHaveNoEffect; - void ReportDiagnostic(Diagnostic diagnostic, MessageDescriptor descriptor, string prefix = "") + void ReportDiagnostic(Diagnostic diagnostic, MessageDescriptor descriptor, string autoPrefix = "") { var display = CSharpDiagnosticFormatter.Instance.Format(diagnostic); - var args = new[] { prefix, display }; + var args = new[] { autoPrefix, display }; _logger.Log(descriptor, args); - if (descriptor.Severity != MessageSeverity.None) + if (autoPrefix != "") + { + errorsToDisplayInApp.Add(MessageDescriptor.RestartingApplicationToApplyChanges.GetMessage()); + } + else if (descriptor.Severity != MessageSeverity.None) { - diagnosticsToDisplayInApp.Add(descriptor.GetMessage(args)); + errorsToDisplayInApp.Add(descriptor.GetMessage(args)); } } @@ -528,7 +548,8 @@ public async ValueTask HandleStaticAssetChangesAsync(IReadOnlyList { var (runningProject, assets) = entry; - await runningProject.Clients.ApplyStaticAssetUpdatesAsync(assets, cancellationToken); + using var processCommunicationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(runningProject.ProcessExitedCancellationToken, cancellationToken); + await runningProject.Clients.ApplyStaticAssetUpdatesAsync(assets, processCommunicationCancellationSource.Token); }); await Task.WhenAll(tasks).WaitAsync(cancellationToken); @@ -539,76 +560,64 @@ public async ValueTask HandleStaticAssetChangesAsync(IReadOnlyList - /// Terminates all processes launched for projects with , + /// Terminates all processes launched for non-root projects with , /// or all running non-root project processes if is null. /// /// Removes corresponding entries from . /// /// Does not terminate the root project. /// + /// All processes (including root) to be restarted. internal async ValueTask> TerminateNonRootProcessesAsync( IEnumerable? projectPaths, CancellationToken cancellationToken) { ImmutableArray projectsToRestart = []; - UpdateRunningProjects(runningProjectsByPath => + lock (_runningProjectsAndUpdatesGuard) { - if (projectPaths == null) - { - projectsToRestart = _runningProjects.SelectMany(entry => entry.Value).Where(p => !p.Options.IsRootProject).ToImmutableArray(); - return _runningProjects.Clear(); - } - - projectsToRestart = projectPaths.SelectMany(path => _runningProjects.TryGetValue(path, out var array) ? array : []).ToImmutableArray(); - return runningProjectsByPath.RemoveRange(projectPaths); - }); + projectsToRestart = projectPaths == null + ? [.. _runningProjects.SelectMany(entry => entry.Value)] + : [.. projectPaths.SelectMany(path => _runningProjects.TryGetValue(path, out var array) ? array : [])]; + } // Do not terminate root process at this time - it would signal the cancellation token we are currently using. // The process will be restarted later on. - var projectsToTerminate = projectsToRestart.Where(p => !p.Options.IsRootProject); - - // wait for all processes to exit to release their resources, so we can rebuild: - _ = await TerminateRunningProjects(projectsToTerminate, cancellationToken); + // Wait for all processes to exit to release their resources, so we can rebuild. + await Task.WhenAll(projectsToRestart.Where(p => !p.Options.IsRootProject).Select(p => p.TerminateAsync(isRestarting: true))).WaitAsync(cancellationToken); return projectsToRestart; } - /// - /// Terminates process of the given . - /// Removes corresponding entries from . - /// - /// Should not be called with the root project. - /// - /// Exit code of the terminated process. - internal async ValueTask TerminateNonRootProcessAsync(RunningProject project, CancellationToken cancellationToken) + private bool RemoveRunningProject(RunningProject project) { - Debug.Assert(!project.Options.IsRootProject); - var projectPath = project.ProjectNode.ProjectInstance.FullPath; - UpdateRunningProjects(runningProjectsByPath => + return UpdateRunningProjects(runningProjectsByPath => { - if (!runningProjectsByPath.TryGetValue(projectPath, out var runningProjects) || - runningProjects.Remove(project) is var updatedRunningProjects && runningProjects == updatedRunningProjects) + if (!runningProjectsByPath.TryGetValue(projectPath, out var runningInstances)) { - _logger.LogDebug("Ignoring an attempt to terminate process {ProcessId} of project '{Path}' that has no associated running processes.", project.ProcessId, projectPath); return runningProjectsByPath; } + var updatedRunningProjects = runningInstances.Remove(project); return updatedRunningProjects is [] ? runningProjectsByPath.Remove(projectPath) : runningProjectsByPath.SetItem(projectPath, updatedRunningProjects); }); - - // wait for all processes to exit to release their resources: - return (await TerminateRunningProjects([project], cancellationToken)).Single(); } - private void UpdateRunningProjects(Func>, ImmutableDictionary>> updater) + private bool UpdateRunningProjects(Func>, ImmutableDictionary>> updater) { lock (_runningProjectsAndUpdatesGuard) { - _runningProjects = updater(_runningProjects); + var newRunningProjects = updater(_runningProjects); + if (newRunningProjects != _runningProjects) + { + _runningProjects = newRunningProjects; + return true; + } + + return false; } } @@ -620,12 +629,6 @@ public bool TryGetRunningProject(string projectPath, out ImmutableArray> TerminateRunningProjects(IEnumerable projects, CancellationToken cancellationToken) - { - // wait for all tasks to complete: - return await Task.WhenAll(projects.Select(p => p.TerminateAsync().AsTask())).WaitAsync(cancellationToken); - } - private static Task ForEachProjectAsync(ImmutableDictionary> projects, Func action, CancellationToken cancellationToken) => Task.WhenAll(projects.SelectMany(entry => entry.Value).Select(project => action(project, cancellationToken))).WaitAsync(cancellationToken); diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs b/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs index 764a371ab30..6f4b8803ed9 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs @@ -108,7 +108,7 @@ public async Task WatchAsync(CancellationToken shutdownCancellationToken) } var projectMap = new ProjectNodeMap(evaluationResult.ProjectGraph, _context.Logger); - compilationHandler = new CompilationHandler(_context.LoggerFactory, _context.Logger, _context.ProcessRunner); + compilationHandler = new CompilationHandler(_context.Logger, _context.ProcessRunner); var scopedCssFileHandler = new ScopedCssFileHandler(_context.Logger, _context.BuildLogger, projectMap, _context.BrowserRefreshServerFactory, _context.Options, _context.EnvironmentOptions); var projectLauncher = new ProjectLauncher(_context, projectMap, compilationHandler, iteration); evaluationResult.ItemExclusions.Report(_context.Logger); @@ -127,6 +127,7 @@ public async Task WatchAsync(CancellationToken shutdownCancellationToken) rootProjectOptions, rootProcessTerminationSource, onOutput: null, + onExit: null, restartOperation: new RestartOperation(_ => throw new InvalidOperationException("Root project shouldn't be restarted")), iterationCancellationToken); @@ -138,7 +139,7 @@ public async Task WatchAsync(CancellationToken shutdownCancellationToken) } // Cancel iteration as soon as the root process exits, so that we don't spent time loading solution, etc. when the process is already dead. - rootRunningProject.ProcessExitedSource.Token.Register(() => iterationCancellationSource.Cancel()); + rootRunningProject.ProcessExitedCancellationToken.Register(() => iterationCancellationSource.Cancel()); if (shutdownCancellationToken.IsCancellationRequested) { @@ -146,11 +147,7 @@ public async Task WatchAsync(CancellationToken shutdownCancellationToken) return; } - try - { - await rootRunningProject.WaitForProcessRunningAsync(iterationCancellationToken); - } - catch (OperationCanceledException) when (rootRunningProject.ProcessExitedSource.Token.IsCancellationRequested) + if (!await rootRunningProject.WaitForProcessRunningAsync(iterationCancellationToken)) { // Process might have exited while we were trying to communicate with it. // Cancel the iteration, but wait for a file change before starting a new one. @@ -384,19 +381,7 @@ await Task.WhenAll( projectsToRestart.Select(async runningProject => { var newRunningProject = await runningProject.RestartOperation(shutdownCancellationToken); - - try - { - await newRunningProject.WaitForProcessRunningAsync(shutdownCancellationToken); - } - catch (OperationCanceledException) when (!shutdownCancellationToken.IsCancellationRequested) - { - // Process might have exited while we were trying to communicate with it. - } - finally - { - runningProject.Dispose(); - } + _ = await newRunningProject.WaitForProcessRunningAsync(shutdownCancellationToken); })) .WaitAsync(shutdownCancellationToken); @@ -546,7 +531,7 @@ async Task> CaptureChangedFilesSnapshot(ImmutableArra if (rootRunningProject != null) { - await rootRunningProject.TerminateAsync(); + await rootRunningProject.TerminateAsync(isRestarting: false); } if (runtimeProcessLauncher != null) @@ -554,8 +539,6 @@ async Task> CaptureChangedFilesSnapshot(ImmutableArra await runtimeProcessLauncher.DisposeAsync(); } - rootRunningProject?.Dispose(); - if (waitForFileChangeBeforeRestarting && !shutdownCancellationToken.IsCancellationRequested && !forceRestartCancellationSource.IsCancellationRequested) diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProcessRunner.cs b/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProcessRunner.cs index 3583dc07b8d..54ae7d13022 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProcessRunner.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProcessRunner.cs @@ -9,12 +9,22 @@ namespace Microsoft.DotNet.Watch { internal sealed class ProcessRunner(TimeSpan processCleanupTimeout) { - private sealed class ProcessState + private sealed class ProcessState(Process process) : IDisposable { + public Process Process { get; } = process; + public int ProcessId; public bool HasExited; + + // True if Ctrl+C was sent to the process on Windows. + public bool SentWindowsCtrlC; + + public void Dispose() + => Process.Dispose(); } + private const int CtlrCExitCode = unchecked((int)0xC000013A); + // For testing purposes only, lock on access. private static readonly HashSet s_runningApplicationProcesses = []; @@ -31,67 +41,32 @@ public static IReadOnlyCollection GetRunningApplicationProcesses() /// public async Task RunAsync(ProcessSpec processSpec, ILogger logger, ProcessLaunchResult? launchResult, CancellationToken processTerminationToken) { - var state = new ProcessState(); var stopwatch = new Stopwatch(); - - var onOutput = processSpec.OnOutput; - - using var process = CreateProcess(processSpec, onOutput, state, logger); - stopwatch.Start(); - Exception? launchException = null; - try - { - if (!process.Start()) - { - throw new InvalidOperationException("Process can't be started."); - } - - state.ProcessId = process.Id; - - if (processSpec.IsUserApplication) - { - lock (s_runningApplicationProcesses) - { - s_runningApplicationProcesses.Add(state.ProcessId); - } - } - - if (onOutput != null) - { - process.BeginOutputReadLine(); - process.BeginErrorReadLine(); - } - } - catch (Exception e) - { - launchException = e; - } - - var argsDisplay = processSpec.GetArgumentsDisplay(); - if (launchException == null) + using var state = TryStartProcessImpl(processSpec, logger); + if (state == null) { - logger.Log(MessageDescriptor.LaunchedProcess, processSpec.Executable, argsDisplay, state.ProcessId); - } - else - { - logger.Log(MessageDescriptor.FailedToLaunchProcess, processSpec.Executable, argsDisplay, launchException.Message); return int.MinValue; } - if (launchResult != null) + if (processSpec.IsUserApplication) { - launchResult.ProcessId = process.Id; + lock (s_runningApplicationProcesses) + { + s_runningApplicationProcesses.Add(state.ProcessId); + } } + launchResult?.ProcessId = state.ProcessId; + int? exitCode = null; try { try { - await process.WaitForExitAsync(processTerminationToken); + await state.Process.WaitForExitAsync(processTerminationToken); } catch (OperationCanceledException) { @@ -99,7 +74,7 @@ public async Task RunAsync(ProcessSpec processSpec, ILogger logger, Process // Either Ctrl+C was pressed or the process is being restarted. // Non-cancellable to not leave orphaned processes around blocking resources: - await TerminateProcessAsync(process, processSpec, state, logger, CancellationToken.None); + await TerminateProcessAsync(state.Process, processSpec, state, logger, CancellationToken.None); } } catch (Exception e) @@ -125,18 +100,18 @@ public async Task RunAsync(ProcessSpec processSpec, ILogger logger, Process try { - exitCode = process.ExitCode; + exitCode = state.Process.ExitCode; } catch { exitCode = null; } - logger.Log(MessageDescriptor.ProcessRunAndExited, process.Id, stopwatch.ElapsedMilliseconds, exitCode); + logger.Log(MessageDescriptor.ProcessRunAndExited, state.ProcessId, stopwatch.ElapsedMilliseconds, exitCode); if (processSpec.IsUserApplication) { - if (exitCode == 0) + if (exitCode == 0 || state.SentWindowsCtrlC && exitCode == CtlrCExitCode) { logger.Log(MessageDescriptor.Exited); } @@ -159,21 +134,28 @@ public async Task RunAsync(ProcessSpec processSpec, ILogger logger, Process return exitCode ?? int.MinValue; } - private static Process CreateProcess(ProcessSpec processSpec, Action? onOutput, ProcessState state, ILogger logger) + internal static Process? TryStartProcess(ProcessSpec processSpec, ILogger logger) + => TryStartProcessImpl(processSpec, logger)?.Process; + + private static ProcessState? TryStartProcessImpl(ProcessSpec processSpec, ILogger logger) { + var onOutput = processSpec.OnOutput; + var process = new Process { EnableRaisingEvents = true, StartInfo = { FileName = processSpec.Executable, - UseShellExecute = false, + UseShellExecute = processSpec.UseShellExecute, WorkingDirectory = processSpec.WorkingDirectory, RedirectStandardOutput = onOutput != null, RedirectStandardError = onOutput != null, } }; + var state = new ProcessState(process); + if (processSpec.IsUserApplication && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { process.StartInfo.CreateNewProcessGroup = true; @@ -229,14 +211,38 @@ private static Process CreateProcess(ProcessSpec processSpec, Action }; } - return process; + var argsDisplay = processSpec.GetArgumentsDisplay(); + + try + { + if (!process.Start()) + { + throw new InvalidOperationException("Process can't be started."); + } + state.ProcessId = process.Id; + + if (onOutput != null) + { + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + } + + logger.Log(MessageDescriptor.LaunchedProcess, processSpec.Executable, argsDisplay, state.ProcessId); + return state; + } + catch (Exception e) + { + logger.Log(MessageDescriptor.FailedToLaunchProcess, processSpec.Executable, argsDisplay, e.Message); + + state.Dispose(); + return null; + } } private async ValueTask TerminateProcessAsync(Process process, ProcessSpec processSpec, ProcessState state, ILogger logger, CancellationToken cancellationToken) { var forceOnly = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !processSpec.IsUserApplication; - // Ctrl+C hasn't been sent. TerminateProcess(process, state, logger, forceOnly); if (forceOnly) @@ -356,7 +362,11 @@ private static void TerminateWindowsProcess(Process process, ProcessState state, else { var error = ProcessUtilities.SendWindowsCtrlCEvent(state.ProcessId); - if (error != null) + if (error == null) + { + state.SentWindowsCtrlC = true; + } + else { logger.Log(MessageDescriptor.FailedToSendSignalToProcess, signalName, state.ProcessId, error); } diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProcessSpec.cs b/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProcessSpec.cs index b780f277002..b3e1eaa1a6a 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProcessSpec.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProcessSpec.cs @@ -8,12 +8,13 @@ internal sealed class ProcessSpec { public string? Executable { get; set; } public string? WorkingDirectory { get; set; } - public Dictionary EnvironmentVariables { get; } = new(); + public Dictionary EnvironmentVariables { get; } = []; public IReadOnlyList? Arguments { get; set; } public string? EscapedArguments { get; set; } public Action? OnOutput { get; set; } public ProcessExitAction? OnExit { get; set; } public CancellationToken CancelOutputCapture { get; set; } + public bool UseShellExecute { get; set; } = false; /// /// True if the process is a user application, false if it is a helper process (e.g. dotnet build). diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProjectLauncher.cs b/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProjectLauncher.cs index 3299710fd18..fb74333ebdd 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProjectLauncher.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/Process/ProjectLauncher.cs @@ -30,6 +30,7 @@ public EnvironmentOptions EnvironmentOptions ProjectOptions projectOptions, CancellationTokenSource processTerminationSource, Action? onOutput, + ProcessExitAction? onExit, RestartOperation restartOperation, CancellationToken cancellationToken) { @@ -66,12 +67,14 @@ public EnvironmentOptions EnvironmentOptions IsUserApplication = true, WorkingDirectory = projectOptions.WorkingDirectory, OnOutput = onOutput, + OnExit = onExit, }; // Stream output lines to the process output reporter. // The reporter synchronizes the output of the process with the logger output, // so that the printed lines don't interleave. - processSpec.OnOutput += line => + // Only send the output to the reporter if no custom output handler was provided (e.g. for Aspire child processes). + processSpec.OnOutput ??= line => { context.ProcessOutputReporter.ReportOutput(context.ProcessOutputReporter.PrefixProcessOutput ? line with { Content = $"[{projectDisplayName}] {line.Content}" } : line); }; @@ -88,7 +91,7 @@ public EnvironmentOptions EnvironmentOptions environmentBuilder[EnvironmentVariables.Names.DotnetWatch] = "1"; environmentBuilder[EnvironmentVariables.Names.DotnetWatchIteration] = (Iteration + 1).ToString(CultureInfo.InvariantCulture); - if (Logger.IsEnabled(LogLevel.Debug)) + if (Logger.IsEnabled(LogLevel.Trace)) { environmentBuilder[EnvironmentVariables.Names.HotReloadDeltaClientLogMessages] = (EnvironmentOptions.SuppressEmojis ? Emoji.Default : Emoji.Agent).GetLogMessagePrefix() + $"[{projectDisplayName}]"; @@ -129,7 +132,4 @@ private static IReadOnlyList GetProcessArguments(ProjectOptions projectO arguments.AddRange(projectOptions.CommandArguments); return arguments; } - - public ValueTask TerminateProcessAsync(RunningProject project, CancellationToken cancellationToken) - => compilationHandler.TerminateNonRootProcessAsync(project, cancellationToken); } diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/Process/RunningProject.cs b/src/sdk/src/BuiltInTools/dotnet-watch/Process/RunningProject.cs index 46ecd2c629a..c2662ceec1f 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/Process/RunningProject.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/Process/RunningProject.cs @@ -3,8 +3,10 @@ using System.Collections.Immutable; +using System.Diagnostics; using Microsoft.Build.Graph; using Microsoft.DotNet.HotReload; +using Microsoft.Extensions.Logging; namespace Microsoft.DotNet.Watch { @@ -19,7 +21,6 @@ internal sealed class RunningProject( CancellationTokenSource processExitedSource, CancellationTokenSource processTerminationSource, RestartOperation restartOperation, - IReadOnlyList disposables, ImmutableArray capabilities) : IDisposable { public readonly ProjectGraphNode ProjectNode = projectNode; @@ -31,44 +32,64 @@ internal sealed class RunningProject( public readonly RestartOperation RestartOperation = restartOperation; /// - /// Cancellation source triggered when the process exits. + /// Cancellation token triggered when the process exits. + /// Stores the token to allow callers to use the token even after the source has been disposed. /// - public readonly CancellationTokenSource ProcessExitedSource = processExitedSource; + public CancellationToken ProcessExitedCancellationToken = processExitedSource.Token; /// - /// Cancellation source to use to terminate the process. + /// Set to true when the process termination is being requested so that it can be restarted within + /// the Hot Reload session (i.e. without restarting the root project). /// - public readonly CancellationTokenSource ProcessTerminationSource = processTerminationSource; + public bool IsRestarting { get; private set; } + + private volatile bool _isDisposed; /// - /// Misc disposable object to dispose when the object is disposed. + /// Disposes the project. Can occur unexpectedly whenever the process exits. + /// Must only be called once per project. /// - private readonly IReadOnlyList _disposables = disposables; - public void Dispose() { - Clients.Dispose(); - ProcessTerminationSource.Dispose(); - ProcessExitedSource.Dispose(); + ObjectDisposedException.ThrowIf(_isDisposed, this); - foreach (var disposable in _disposables) - { - disposable.Dispose(); - } + _isDisposed = true; + processExitedSource.Cancel(); + + Clients.Dispose(); + processTerminationSource.Dispose(); + processExitedSource.Dispose(); } /// /// Waits for the application process to start. /// Ensures that the build has been complete and the build outputs are available. + /// Returns false if the process has exited before the connection was established. /// - public async ValueTask WaitForProcessRunningAsync(CancellationToken cancellationToken) + public async ValueTask WaitForProcessRunningAsync(CancellationToken cancellationToken) { - await Clients.WaitForConnectionEstablishedAsync(cancellationToken); + using var processCommunicationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ProcessExitedCancellationToken); + + try + { + await Clients.WaitForConnectionEstablishedAsync(processCommunicationCancellationSource.Token); + return true; + } + catch (OperationCanceledException) when (ProcessExitedCancellationToken.IsCancellationRequested) + { + return false; + } } - public async ValueTask TerminateAsync() + public async Task TerminateAsync(bool isRestarting) { - ProcessTerminationSource.Cancel(); + IsRestarting = isRestarting; + + if (!_isDisposed) + { + processTerminationSource.Cancel(); + } + return await RunningProcess; } } diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/Program.cs b/src/sdk/src/BuiltInTools/dotnet-watch/Program.cs index b2b9bd03bbd..f67a360a3a3 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/Program.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/Program.cs @@ -240,7 +240,7 @@ internal DotNetWatchContext CreateContext(ProcessRunner processRunner) EnvironmentOptions = environmentOptions, RootProjectOptions = rootProjectOptions, BrowserRefreshServerFactory = new BrowserRefreshServerFactory(), - BrowserLauncher = new BrowserLauncher(logger, environmentOptions), + BrowserLauncher = new BrowserLauncher(logger, processOutputReporter, environmentOptions), }; } diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/Properties/launchSettings.json b/src/sdk/src/BuiltInTools/dotnet-watch/Properties/launchSettings.json index b6981fd0ae9..9e28729eb80 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/Properties/launchSettings.json +++ b/src/sdk/src/BuiltInTools/dotnet-watch/Properties/launchSettings.json @@ -3,7 +3,7 @@ "dotnet-watch": { "commandName": "Project", "commandLineArgs": "--verbose -bl", - "workingDirectory": "$(RepoRoot)src\\Assets\\TestProjects\\BlazorWasmWithLibrary\\blazorwasm", + "workingDirectory": "C:\\bugs\\9756\\aspire-watch-start-issue\\Aspire.AppHost", "environmentVariables": { "DOTNET_WATCH_DEBUG_SDK_DIRECTORY": "$(RepoRoot)artifacts\\bin\\redist\\$(Configuration)\\dotnet\\sdk\\$(Version)", "DCP_IDE_REQUEST_TIMEOUT_SECONDS": "100000", diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/UI/ConsoleReporter.cs b/src/sdk/src/BuiltInTools/dotnet-watch/UI/ConsoleReporter.cs index 84cc357ad35..198e518590b 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/UI/ConsoleReporter.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/UI/ConsoleReporter.cs @@ -56,24 +56,24 @@ public void Report(EventId id, Emoji emoji, MessageSeverity severity, string mes { case MessageSeverity.Error: // Use stdout for error messages to preserve ordering with respect to other output. - WriteLine(console.Out, message, ConsoleColor.Red, emoji); + WriteLine(console.Error, message, ConsoleColor.Red, emoji); break; case MessageSeverity.Warning: - WriteLine(console.Out, message, ConsoleColor.Yellow, emoji); + WriteLine(console.Error, message, ConsoleColor.Yellow, emoji); break; case MessageSeverity.Output: if (!IsQuiet) { - WriteLine(console.Out, message, color: null, emoji); + WriteLine(console.Error, message, color: null, emoji); } break; case MessageSeverity.Verbose: if (IsVerbose) { - WriteLine(console.Out, message, ConsoleColor.DarkGray, emoji); + WriteLine(console.Error, message, ConsoleColor.DarkGray, emoji); } break; } diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/UI/IReporter.cs b/src/sdk/src/BuiltInTools/dotnet-watch/UI/IReporter.cs index c6f64394da8..3d60e288a97 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/UI/IReporter.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/UI/IReporter.cs @@ -209,9 +209,12 @@ public MessageDescriptor WithSeverityWhen(MessageSeverity severity, bool conditi public static readonly MessageDescriptor UpdatingDiagnostics = Create(LogEvents.UpdatingDiagnostics, Emoji.Default); public static readonly MessageDescriptor FailedToReceiveResponseFromConnectedBrowser = Create(LogEvents.FailedToReceiveResponseFromConnectedBrowser, Emoji.Default); public static readonly MessageDescriptor NoBrowserConnected = Create(LogEvents.NoBrowserConnected, Emoji.Default); + public static readonly MessageDescriptor LaunchingBrowser = Create("Launching browser: {0} {1}", Emoji.Default, MessageSeverity.Verbose); public static readonly MessageDescriptor RefreshingBrowser = Create(LogEvents.RefreshingBrowser, Emoji.Default); public static readonly MessageDescriptor ReloadingBrowser = Create(LogEvents.ReloadingBrowser, Emoji.Default); public static readonly MessageDescriptor RefreshServerRunningAt = Create(LogEvents.RefreshServerRunningAt, Emoji.Default); + public static readonly MessageDescriptor ConnectedToRefreshServer = Create(LogEvents.ConnectedToRefreshServer, Emoji.Default); + public static readonly MessageDescriptor RestartingApplicationToApplyChanges = Create("Restarting application to apply changes ...", Emoji.Default, MessageSeverity.Output); public static readonly MessageDescriptor IgnoringChangeInHiddenDirectory = Create("Ignoring change in hidden directory '{0}': {1} '{2}'", Emoji.Watch, MessageSeverity.Verbose); public static readonly MessageDescriptor IgnoringChangeInOutputDirectory = Create("Ignoring change in output directory: {0} '{1}'", Emoji.Watch, MessageSeverity.Verbose); public static readonly MessageDescriptor IgnoringChangeInExcludedFile = Create("Ignoring change in excluded file '{0}': {1}. Path matches {2} glob '{3}' set in '{4}'.", Emoji.Watch, MessageSeverity.Verbose); diff --git a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs index 69b532afb0b..0c5aef16136 100644 --- a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs +++ b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs @@ -35,6 +35,14 @@ public static class Constants public const string Identity = nameof(Identity); public const string FullPath = nameof(FullPath); + // MSBuild CLI flags + + /// + /// Disables the live-updating node display in the terminal logger, which is useful for LLM/agentic environments. + /// + public const string TerminalLogger_DisableNodeDisplay = "-tlp:DISABLENODEDISPLAY"; + + public static readonly string ProjectArgumentName = ""; public static readonly string SolutionArgumentName = ""; public static readonly string ToolPackageArgumentName = ""; diff --git a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs index 97e7abd086c..e0dca709ac3 100644 --- a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs +++ b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs @@ -56,7 +56,6 @@ public MSBuildForwardingAppWithoutLogging(MSBuildArgs msbuildArgs, string? msbui msbuildArgs.OtherMSBuildArgs.Add("-nologo"); } string? tlpDefault = TerminalLoggerDefault; - // new for .NET 9 - default TL to auto (aka enable in non-CI scenarios) if (string.IsNullOrWhiteSpace(tlpDefault)) { tlpDefault = "auto"; diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs index ecf9c58147f..0b1407d3d11 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs @@ -1439,6 +1439,17 @@ internal static string PostAction_ModifyJson_Error_NoJsonFile { } } + /// + /// Looks up a localized string similar to The result of parsing the following JSON was 'null': + /// + ///{0}. + /// + internal static string PostAction_ModifyJson_Error_NullJson { + get { + return ResourceManager.GetString("PostAction_ModifyJson_Error_NullJson", resourceCulture); + } + } + /// /// Looks up a localized string similar to Parent property path '{0}' could not be traversed.. /// diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx index 01b59dfe883..d08a680ebae 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx @@ -953,4 +953,10 @@ The header is followed by the list of parameters and their errors (might be seve Attempting to find json file '{0}' in '{1}' - + + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + + \ No newline at end of file diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs index 80ca2340291..f517a6b363b 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs @@ -19,7 +19,9 @@ internal class AddJsonPropertyPostActionProcessor : PostActionProcessorBase private const string ParentPropertyPathArgument = "parentPropertyPath"; private const string NewJsonPropertyNameArgument = "newJsonPropertyName"; private const string NewJsonPropertyValueArgument = "newJsonPropertyValue"; - private const string DetectRepoRootForFileCreation = "detectRepositoryRootForFileCreation"; + private const string DetectRepoRoot = "detectRepositoryRoot"; + private const string IncludeAllDirectoriesInSearch = "includeAllDirectoriesInSearch"; + private const string IncludeAllParentDirectoriesInSearch = "includeAllParentDirectoriesInSearch"; private static readonly JsonSerializerOptions SerializerOptions = new() { @@ -87,7 +89,33 @@ protected override bool ProcessInternal( return false; } - IReadOnlyList jsonFiles = FindFilesInCurrentFolderOrParentFolder(environment.Host.FileSystem, outputBasePath, jsonFileName); + if (!bool.TryParse(action.Args.GetValueOrDefault(DetectRepoRoot, "false"), out bool detectRepoRoot)) + { + Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, DetectRepoRoot)); + return false; + } + + if (!bool.TryParse(action.Args.GetValueOrDefault(IncludeAllDirectoriesInSearch, "true"), out bool includeAllDirectories)) + { + Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, IncludeAllDirectoriesInSearch)); + return false; + } + + string? repoRoot = detectRepoRoot ? GetRootDirectory(environment.Host.FileSystem, outputBasePath) : null; + + if (!bool.TryParse(action.Args.GetValueOrDefault(IncludeAllParentDirectoriesInSearch, "false"), out bool includeAllParentDirectories)) + { + Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, IncludeAllParentDirectoriesInSearch)); + return false; + } + + IReadOnlyList jsonFiles = FindFilesInCurrentFolderOrParentFolder( + environment.Host.FileSystem, + outputBasePath, + jsonFileName, + includeAllDirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly, + includeAllParentDirectories ? int.MaxValue : 1, + repoRoot); if (jsonFiles.Count == 0) { @@ -103,13 +131,7 @@ protected override bool ProcessInternal( return false; } - if (!bool.TryParse(action.Args.GetValueOrDefault(DetectRepoRootForFileCreation, "false"), out bool detectRepoRoot)) - { - Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, DetectRepoRootForFileCreation)); - return false; - } - - string newJsonFilePath = Path.Combine(detectRepoRoot ? GetRootDirectory(environment.Host.FileSystem, outputBasePath) : outputBasePath, jsonFileName); + string newJsonFilePath = Path.Combine(repoRoot ?? outputBasePath, jsonFileName); environment.Host.FileSystem.WriteAllText(newJsonFilePath, "{}"); jsonFiles = new List { newJsonFilePath }; } @@ -150,17 +172,19 @@ protected override bool ProcessInternal( private static JsonNode? AddElementToJson(IPhysicalFileSystem fileSystem, string targetJsonFile, string? propertyPath, string propertyPathSeparator, string newJsonPropertyName, string newJsonPropertyValue, IPostAction action) { - JsonNode? jsonContent = JsonNode.Parse(fileSystem.ReadAllText(targetJsonFile), nodeOptions: null, documentOptions: DeserializerOptions); + var fileContent = fileSystem.ReadAllText(targetJsonFile); + JsonNode? jsonContent = JsonNode.Parse(fileContent, nodeOptions: null, documentOptions: DeserializerOptions); if (jsonContent == null) { + Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_NullJson, fileContent)); return null; } if (!bool.TryParse(action.Args.GetValueOrDefault(AllowPathCreationArgument, "false"), out bool createPath)) { Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, AllowPathCreationArgument)); - return false; + return null; } JsonNode? parentProperty = FindJsonNode(jsonContent, propertyPath, propertyPathSeparator, createPath); @@ -216,7 +240,10 @@ protected override bool ProcessInternal( private static string[] FindFilesInCurrentFolderOrParentFolder( IPhysicalFileSystem fileSystem, string startPath, - string matchPattern) + string matchPattern, + SearchOption searchOption, + int maxUpLevels, + string? repoRoot) { string? directory = fileSystem.DirectoryExists(startPath) ? startPath : Path.GetDirectoryName(startPath); @@ -230,17 +257,24 @@ private static string[] FindFilesInCurrentFolderOrParentFolder( do { Reporter.Verbose.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Verbose_AttemptingToFindJsonFile, matchPattern, directory)); - string[] filesInDir = fileSystem.EnumerateFileSystemEntries(directory, matchPattern, SearchOption.AllDirectories).ToArray(); + string[] filesInDir = fileSystem.EnumerateFileSystemEntries(directory, matchPattern, searchOption).ToArray(); if (filesInDir.Length > 0) { return filesInDir; } + if (repoRoot is not null && directory == repoRoot) + { + // The post action wants to detect the "repo root". + // We have already processed up to the repo root and didn't find any matching files, so we shouldn't go up any further. + return Array.Empty(); + } + directory = Path.GetPathRoot(directory) != directory ? Directory.GetParent(directory)?.FullName : null; numberOfUpLevels++; } - while (directory != null && numberOfUpLevels <= 1); + while (directory != null && numberOfUpLevels <= maxUpLevels); return Array.Empty(); } diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf index 45f6d58a1ba..ecb19bae658 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve V řešení se nepovedlo najít soubor JSON. + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. Cestu k nadřazené vlastnosti „{0}“ nelze projít. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf index eb67ab8bf9b..0b82cc14850 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve Die JSON-Datei wurde in der Projektmappe nicht gefunden. + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. Der übergeordnete Eigenschaftenpfad "{0}" konnte nicht durchlaufen werden. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf index 748e66f30a0..c76d9428883 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve No se encuentra el archivo JSON en la solución + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. No se pudo atravesar la ruta de acceso de la propiedad primaria '{0}'. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf index d86722e36e6..3dd088fe92f 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve Impossible de trouver le fichier json dans la solution + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. Le chemin de la propriété parente '{0}' n'a pas pu être traversé. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf index 45d8e4f02e4..5022ad18a8c 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve Non è possibile trovare il file JSON nella soluzione + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. Impossibile attraversare il percorso della proprietà padre '{0}'. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf index 2f9a5c77a25..e27c0eea775 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve ソリューションで JSON ファイルが見つかりません + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. 親プロパティのパス '{0}' を走査できませんでした。 diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf index 11699454506..28e0b7ef6ea 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve 솔루션에서 json 파일을 찾을 수 없습니다. + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. '{0}' 부모 속성 경로를 트래버스할 수 없습니다. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf index 6e5167124b3..edc3a399520 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve Nie można odnaleźć pliku JSON w rozwiązaniu + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. Nie można przejść przez ścieżkę właściwości nadrzędnej „{0}”. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf index 24f89179cb8..22b848dd30e 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve Não é possível encontrar o arquivo json na solução + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. O caminho da propriedade pai '{0}' não pôde ser percorrido. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf index 6578a4d5bf1..b41a1a5ac24 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve Не удалось найти файл JSON в решении + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. Не удалось просмотреть путь к родительскому свойству "{0}". diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf index a0d71cff2b9..158582a214b 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve Çözümde json dosyası bulunamıyor + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. Üst özellik '{0}' yolu geçirilemedi. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf index f75d8ad68da..2df9444a65e 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve 在解决方案中找不到 json 文件 + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. 无法遍历父属性路径“{0}”。 diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf index 56c64a9d9b9..1c17c1adc32 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf @@ -850,6 +850,15 @@ The header is followed by the list of parameters and their errors (might be seve 在解決方案中找不到 JSON 檔案 + + The result of parsing the following JSON was 'null': + +{0} + The result of parsing the following JSON was 'null': + +{0} + {0} is the JSON that is being parsed. + Parent property path '{0}' could not be traversed. 無法周遊父屬性路徑 '{0}'。 diff --git a/src/sdk/src/Cli/dotnet/CliStrings.resx b/src/sdk/src/Cli/dotnet/CliStrings.resx index 7b118637944..bd4864527b9 100644 --- a/src/sdk/src/Cli/dotnet/CliStrings.resx +++ b/src/sdk/src/Cli/dotnet/CliStrings.resx @@ -817,7 +817,7 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. Package reference id and version must not be null. @@ -838,4 +838,7 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is Only one .nuspec file can be packed at a time + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + \ No newline at end of file diff --git a/src/sdk/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/sdk/src/Cli/dotnet/Commands/CliCommandStrings.resx index 3a3fab487f8..74001a13dfe 100644 --- a/src/sdk/src/Cli/dotnet/Commands/CliCommandStrings.resx +++ b/src/sdk/src/Cli/dotnet/Commands/CliCommandStrings.resx @@ -804,8 +804,9 @@ See https://aka.ms/dotnet-test/mtp for more information. Discovering tests from - - .NET Test Command + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Downloading pack {0} version {1} to offline cache {2}... @@ -1619,6 +1620,9 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man Duplicate directives are not supported: {0} {0} is the directive type and name. + + Directives currently cannot contain double quotes ("). + Cannot specify option '{0}' when also using '-' to read the file from standard input. {0} is an option name like '--no-build'. @@ -1994,8 +1998,9 @@ Your project targets multiple frameworks. Specify which framework to run using ' Specify a temporary directory for this command to download and extract NuGet packages (must be secure). - - .NET Test Driver + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Run test(s), without displaying Microsoft Testplatform banner @@ -2698,4 +2703,25 @@ Proceed? Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. {Locked="ExecutionId"} - \ No newline at end of file + + error: + + + total: + + + retried + + + failed: + + + succeeded: + + + skipped: + + + duration: + + diff --git a/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs b/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs index 67c2a47f105..3055de0883f 100644 --- a/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs +++ b/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Reflection; +using Microsoft.DotNet.Cli.Commands.Run; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils.Extensions; @@ -14,6 +15,9 @@ public class MSBuildForwardingApp : CommandBase private readonly MSBuildForwardingAppWithoutLogging _forwardingAppWithoutLogging; + /// + /// Adds the CLI's telemetry logger to the MSBuild arguments if telemetry is enabled. + /// private static MSBuildArgs ConcatTelemetryLogger(MSBuildArgs msbuildArgs) { if (Telemetry.Telemetry.CurrentSessionId != null) @@ -45,8 +49,9 @@ public MSBuildForwardingApp(IEnumerable rawMSBuildArgs, string? msbuildP public MSBuildForwardingApp(MSBuildArgs msBuildArgs, string? msbuildPath = null, bool includeLogo = false) { + var modifiedMSBuildArgs = CommonRunHelpers.AdjustMSBuildForLLMs(ConcatTelemetryLogger(msBuildArgs)); _forwardingAppWithoutLogging = new MSBuildForwardingAppWithoutLogging( - ConcatTelemetryLogger(msBuildArgs), + modifiedMSBuildArgs, msbuildPath: msbuildPath, includeLogo: includeLogo); diff --git a/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs b/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs index 2fa89c8d593..00e73d0db6b 100644 --- a/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs +++ b/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs @@ -1,8 +1,6 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - using System.Globalization; using Microsoft.Build.Framework; using Microsoft.DotNet.Cli.Telemetry; @@ -15,7 +13,7 @@ public sealed class MSBuildLogger : INodeLogger { private readonly IFirstTimeUseNoticeSentinel _sentinel = new FirstTimeUseNoticeSentinel(); - private readonly ITelemetry _telemetry; + private readonly ITelemetry? _telemetry; internal const string TargetFrameworkTelemetryEventName = "targetframeworkeval"; internal const string BuildTelemetryEventName = "build"; @@ -67,7 +65,7 @@ public MSBuildLogger() { try { - string sessionId = + string? sessionId = Environment.GetEnvironmentVariable(MSBuildForwardingApp.TelemetrySessionIdEnvironmentVariableName); if (sessionId != null) @@ -133,11 +131,11 @@ private void OnBuildFinished(object sender, BuildFinishedEventArgs e) SendAggregatedEventsOnBuildFinished(_telemetry); } - internal void SendAggregatedEventsOnBuildFinished(ITelemetry telemetry) + internal void SendAggregatedEventsOnBuildFinished(ITelemetry? telemetry) { if (_aggregatedEvents.TryGetValue(TaskFactoryTelemetryAggregatedEventName, out var taskFactoryData)) { - Dictionary taskFactoryProperties = ConvertToStringDictionary(taskFactoryData); + var taskFactoryProperties = ConvertToStringDictionary(taskFactoryData); TrackEvent(telemetry, $"msbuild/{TaskFactoryTelemetryAggregatedEventName}", taskFactoryProperties, toBeHashed: [], toBeMeasured: []); _aggregatedEvents.Remove(TaskFactoryTelemetryAggregatedEventName); @@ -145,16 +143,16 @@ internal void SendAggregatedEventsOnBuildFinished(ITelemetry telemetry) if (_aggregatedEvents.TryGetValue(TasksTelemetryAggregatedEventName, out var tasksData)) { - Dictionary tasksProperties = ConvertToStringDictionary(tasksData); + var tasksProperties = ConvertToStringDictionary(tasksData); TrackEvent(telemetry, $"msbuild/{TasksTelemetryAggregatedEventName}", tasksProperties, toBeHashed: [], toBeMeasured: []); _aggregatedEvents.Remove(TasksTelemetryAggregatedEventName); } } - private static Dictionary ConvertToStringDictionary(Dictionary properties) + private static Dictionary ConvertToStringDictionary(Dictionary properties) { - Dictionary stringProperties = new(); + Dictionary stringProperties = new(); foreach (var kvp in properties) { stringProperties[kvp.Key] = kvp.Value.ToString(CultureInfo.InvariantCulture); @@ -165,9 +163,14 @@ private static Dictionary ConvertToStringDictionary(Dictionary eventData)) + if (args.EventName == null || args.Properties == null) { - eventData = new Dictionary(); + return; + } + + if (!_aggregatedEvents.TryGetValue(args.EventName, out var eventData)) + { + eventData = []; _aggregatedEvents[args.EventName] = eventData; } @@ -187,58 +190,39 @@ internal void AggregateEvent(TelemetryEventArgs args) } } - internal static void FormatAndSend(ITelemetry telemetry, TelemetryEventArgs args) + internal static void FormatAndSend(ITelemetry? telemetry, TelemetryEventArgs args) { switch (args.EventName) { case TargetFrameworkTelemetryEventName: - { - var newEventName = $"msbuild/{TargetFrameworkTelemetryEventName}"; - Dictionary maskedProperties = []; - - foreach (var key in new[] { - TargetFrameworkVersionTelemetryPropertyKey, - RuntimeIdentifierTelemetryPropertyKey, - SelfContainedTelemetryPropertyKey, - UseApphostTelemetryPropertyKey, - OutputTypeTelemetryPropertyKey, - UseArtifactsOutputTelemetryPropertyKey, - ArtifactsPathLocationTypeTelemetryPropertyKey - }) - { - if (args.Properties.TryGetValue(key, out string value)) - { - maskedProperties.Add(key, Sha256Hasher.HashWithNormalizedCasing(value)); - } - } - - telemetry.TrackEvent(newEventName, maskedProperties, measurements: null); - break; - } + TrackEvent(telemetry, $"msbuild/{TargetFrameworkTelemetryEventName}", args.Properties); + break; case BuildTelemetryEventName: TrackEvent(telemetry, $"msbuild/{BuildTelemetryEventName}", args.Properties, toBeHashed: ["ProjectPath", "BuildTarget"], - toBeMeasured: ["BuildDurationInMilliseconds", "InnerBuildDurationInMilliseconds"]); + toBeMeasured: ["BuildDurationInMilliseconds", "InnerBuildDurationInMilliseconds"] + ); break; case LoggingConfigurationTelemetryEventName: TrackEvent(telemetry, $"msbuild/{LoggingConfigurationTelemetryEventName}", args.Properties, - toBeHashed: [], - toBeMeasured: ["FileLoggersCount"]); + toBeMeasured: ["FileLoggersCount"] + ); break; case BuildcheckAcquisitionFailureEventName: TrackEvent(telemetry, $"msbuild/{BuildcheckAcquisitionFailureEventName}", args.Properties, - toBeHashed: ["AssemblyName", "ExceptionType", "ExceptionMessage"], - toBeMeasured: []); + toBeHashed: ["AssemblyName", "ExceptionType", "ExceptionMessage"] + ); break; case BuildcheckRunEventName: TrackEvent(telemetry, $"msbuild/{BuildcheckRunEventName}", args.Properties, - toBeHashed: [], - toBeMeasured: ["TotalRuntimeInMilliseconds"]); + toBeMeasured: ["TotalRuntimeInMilliseconds"] + ); break; case BuildcheckRuleStatsEventName: TrackEvent(telemetry, $"msbuild/{BuildcheckRuleStatsEventName}", args.Properties, toBeHashed: ["RuleId", "CheckFriendlyName"], - toBeMeasured: ["TotalRuntimeInMilliseconds"]); + toBeMeasured: ["TotalRuntimeInMilliseconds"] + ); break; // Pass through events that don't need special handling case SdkTaskBaseCatchExceptionTelemetryEventName: @@ -248,7 +232,7 @@ internal static void FormatAndSend(ITelemetry telemetry, TelemetryEventArgs args case SdkContainerPublishBaseImageInferenceEventName: case SdkContainerPublishSuccessEventName: case SdkContainerPublishErrorEventName: - TrackEvent(telemetry, args.EventName, args.Properties, [], []); + TrackEvent(telemetry, args.EventName, args.Properties); break; default: // Ignore unknown events @@ -256,33 +240,44 @@ internal static void FormatAndSend(ITelemetry telemetry, TelemetryEventArgs args } } - private static void TrackEvent(ITelemetry telemetry, string eventName, IDictionary eventProperties, string[] toBeHashed, string[] toBeMeasured) + private static void TrackEvent(ITelemetry? telemetry, string eventName, IDictionary eventProperties, string[]? toBeHashed = null, string[]? toBeMeasured = null) { - Dictionary properties = null; - Dictionary measurements = null; + if (telemetry == null || !telemetry.Enabled) + { + return; + } - foreach (var propertyToBeHashed in toBeHashed) + Dictionary? properties = null; + Dictionary? measurements = null; + + if (toBeHashed is not null) { - if (eventProperties.TryGetValue(propertyToBeHashed, out string value)) + foreach (var propertyToBeHashed in toBeHashed) { - // Lets lazy allocate in case there is tons of telemetry - properties ??= new Dictionary(eventProperties); - properties[propertyToBeHashed] = Sha256Hasher.HashWithNormalizedCasing(value); + if (eventProperties.TryGetValue(propertyToBeHashed, out var value)) + { + // Lets lazy allocate in case there is tons of telemetry + properties ??= new(eventProperties); + properties[propertyToBeHashed] = Sha256Hasher.HashWithNormalizedCasing(value!); + } } } - foreach (var propertyToBeMeasured in toBeMeasured) + if (toBeMeasured is not null) { - if (eventProperties.TryGetValue(propertyToBeMeasured, out string value)) + foreach (var propertyToBeMeasured in toBeMeasured) { - // Lets lazy allocate in case there is tons of telemetry - properties ??= new Dictionary(eventProperties); - properties.Remove(propertyToBeMeasured); - if (double.TryParse(value, CultureInfo.InvariantCulture, out double realValue)) + if (eventProperties.TryGetValue(propertyToBeMeasured, out var value)) { // Lets lazy allocate in case there is tons of telemetry - measurements ??= []; - measurements[propertyToBeMeasured] = realValue; + properties ??= new(eventProperties); + properties.Remove(propertyToBeMeasured); + if (double.TryParse(value, CultureInfo.InvariantCulture, out double realValue)) + { + // Lets lazy allocate in case there is tons of telemetry + measurements ??= []; + measurements[propertyToBeMeasured] = realValue; + } } } } @@ -316,5 +311,5 @@ public void Shutdown() public LoggerVerbosity Verbosity { get; set; } - public string Parameters { get; set; } + public string? Parameters { get; set; } } diff --git a/src/sdk/src/Cli/dotnet/Commands/Package/Add/PackageAddCommand.cs b/src/sdk/src/Cli/dotnet/Commands/Package/Add/PackageAddCommand.cs index d1c73fb5bb1..dc94f892abd 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Package/Add/PackageAddCommand.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Package/Add/PackageAddCommand.cs @@ -163,10 +163,12 @@ private int ExecuteForFileBasedApp(string path) } } - bool hasVersion = _packageId.HasVersion; + string? specifiedVersion = _packageId.HasVersion + ? _packageId.VersionRange?.OriginalString ?? string.Empty + : _parseResult.GetValue(PackageAddCommandParser.VersionOption); bool prerelease = _parseResult.GetValue(PackageAddCommandParser.PrereleaseOption); - if (hasVersion && prerelease) + if (specifiedVersion != null && prerelease) { throw new GracefulException(CliCommandStrings.PrereleaseAndVersionAreNotSupportedAtTheSameTime); } @@ -193,11 +195,7 @@ private int ExecuteForFileBasedApp(string path) // Set initial version to Directory.Packages.props and/or C# file // (we always need to add the package reference to the C# file but when CPM is enabled, it's added without a version). - string version = hasVersion - ? _packageId.VersionRange?.OriginalString ?? string.Empty - : (prerelease - ? "*-*" - : "*"); + string version = specifiedVersion ?? (prerelease ? "*-*" : "*"); bool skipUpdate = false; var central = SetCentralVersion(version); var local = SetLocalVersion(central != null ? null : version); @@ -214,7 +212,7 @@ private int ExecuteForFileBasedApp(string path) } // If no version was specified by the user, save the actually restored version. - if (!hasVersion && !skipUpdate) + if (specifiedVersion == null && !skipUpdate) { var projectAssetsFile = projectInstance.GetProperty("ProjectAssetsFile")?.EvaluatedValue; if (!File.Exists(projectAssetsFile)) @@ -306,7 +304,7 @@ void Update(string value) // If user didn't specify a version and a version is already specified in Directory.Packages.props, // don't update the Directory.Packages.props (that's how the project-based equivalent behaves as well). - if (!hasVersion) + if (specifiedVersion == null) { skipUpdate = true; return (Revert: NoOp, Update: Unreachable, Save: Revert); diff --git a/src/sdk/src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs b/src/sdk/src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs index e18a20cbab2..f1bc3ab7d65 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Immutable; using System.CommandLine; using System.Diagnostics.CodeAnalysis; using Microsoft.Build.Evaluation; @@ -71,8 +72,9 @@ public override int Execute() { using var stream = File.Open(projectFile, FileMode.Create, FileAccess.Write); using var writer = new StreamWriter(stream, Encoding.UTF8); - VirtualProjectBuildingCommand.WriteProjectFile(writer, directives, isVirtualProject: false, - userSecretsId: DetermineUserSecretsId()); + VirtualProjectBuildingCommand.WriteProjectFile(writer, UpdateDirectives(directives), isVirtualProject: false, + userSecretsId: DetermineUserSecretsId(), + excludeDefaultProperties: FindDefaultPropertiesToExclude()); } // Copy or move over included items. @@ -161,6 +163,40 @@ void CopyFile(string source, string target) var actualValue = projectInstance.GetPropertyValue("UserSecretsId"); return implicitValue == actualValue ? actualValue : null; } + + ImmutableArray UpdateDirectives(ImmutableArray directives) + { + var result = ImmutableArray.CreateBuilder(directives.Length); + + foreach (var directive in directives) + { + // Fixup relative project reference paths (they need to be relative to the output directory instead of the source directory). + if (directive is CSharpDirective.Project project && + !Path.IsPathFullyQualified(project.Name)) + { + var modified = project.WithName(Path.GetRelativePath(relativeTo: targetDirectory, path: project.Name)); + result.Add(modified); + } + else + { + result.Add(directive); + } + } + + return result.DrainToImmutable(); + } + + IEnumerable FindDefaultPropertiesToExclude() + { + foreach (var (name, defaultValue) in VirtualProjectBuildingCommand.DefaultProperties) + { + string projectValue = projectInstance.GetPropertyValue(name); + if (!string.Equals(projectValue, defaultValue, StringComparison.OrdinalIgnoreCase)) + { + yield return name; + } + } + } } private string DetermineOutputDirectory(string file) diff --git a/src/sdk/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.Generated.cs b/src/sdk/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.Generated.cs index e7762086e68..d53f7052b75 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.Generated.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.Generated.cs @@ -202,7 +202,6 @@ private IEnumerable GetCscArguments( "/deterministic+", "/langversion:14.0", "/features:FileBasedProgram", - $"/analyzerconfig:{SdkPath}/Sdks/Microsoft.NET.Sdk/codestyle/cs/build/config/analysislevelstyle_default.globalconfig", $"/analyzerconfig:{objDir}/{fileNameWithoutExtension}.GeneratedMSBuildEditorConfig.editorconfig", $"/analyzerconfig:{SdkPath}/Sdks/Microsoft.NET.Sdk/analyzers/build/config/analysislevel_10_default.globalconfig", $"/analyzer:{SdkPath}/Sdks/Microsoft.NET.Sdk/targets/../analyzers/Microsoft.CodeAnalysis.CSharp.NetAnalyzers.dll", diff --git a/src/sdk/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs b/src/sdk/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs index dffbbc0bfab..64d2b8a1075 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs @@ -17,7 +17,6 @@ internal static class CommonRunHelpers public static Dictionary GetGlobalPropertiesFromArgs(MSBuildArgs msbuildArgs) { var globalProperties = msbuildArgs.GlobalProperties?.ToDictionary() ?? new Dictionary(StringComparer.OrdinalIgnoreCase); - globalProperties[Constants.EnableDefaultItems] = "false"; // Disable default item globbing to improve performance globalProperties[Constants.MSBuildExtensionsPath] = AppContext.BaseDirectory; return globalProperties; } @@ -27,4 +26,29 @@ public static string GetPropertiesLaunchSettingsPath(string directoryPath, strin public static string GetFlatLaunchSettingsPath(string directoryPath, string projectNameWithoutExtension) => Path.Join(directoryPath, $"{projectNameWithoutExtension}.run.json"); + + + /// + /// Applies adjustments to MSBuild arguments to better suit LLM/agentic environments, if such an environment is detected. + /// + public static MSBuildArgs AdjustMSBuildForLLMs(MSBuildArgs msbuildArgs) + { + if (new Telemetry.LLMEnvironmentDetectorForTelemetry().IsLLMEnvironment()) + { + // disable the live-update display of the TerminalLogger, which wastes tokens + return msbuildArgs.CloneWithAdditionalArgs(Constants.TerminalLogger_DisableNodeDisplay); + } + else + { + return msbuildArgs; + } + } + + /// + /// Creates a TerminalLogger or ConsoleLogger based on the provided MSBuild arguments. + /// If the environment is detected to be an LLM environment, the logger is adjusted to + /// better suit that environment. + /// + public static Microsoft.Build.Framework.ILogger GetConsoleLogger(MSBuildArgs args) => + Microsoft.Build.Logging.TerminalLogger.CreateTerminalOrConsoleLogger([.. AdjustMSBuildForLLMs(args).OtherMSBuildArgs]); } diff --git a/src/sdk/src/Cli/dotnet/Commands/Run/FileBasedAppSourceEditor.cs b/src/sdk/src/Cli/dotnet/Commands/Run/FileBasedAppSourceEditor.cs index 402da626784..45fa0380aee 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Run/FileBasedAppSourceEditor.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Run/FileBasedAppSourceEditor.cs @@ -86,7 +86,8 @@ private TextChange DetermineAddChange(CSharpDirective directive) { // Find one that has the same kind and name. // If found, we will replace it with the new directive. - if (directive is CSharpDirective.Named named && + var named = directive as CSharpDirective.Named; + if (named != null && Directives.OfType().FirstOrDefault(d => NamedDirectiveComparer.Instance.Equals(d, named)) is { } toReplace) { return new TextChange(toReplace.Info.Span, newText: directive.ToString() + NewLine); @@ -99,6 +100,14 @@ private TextChange DetermineAddChange(CSharpDirective directive) { if (existingDirective.GetType() == directive.GetType()) { + // Add named directives in sorted order. + if (named != null && + existingDirective is CSharpDirective.Named existingNamed && + string.CompareOrdinal(existingNamed.Name, named.Name) > 0) + { + break; + } + addAfter = existingDirective; } else if (addAfter != null) @@ -120,7 +129,7 @@ private TextChange DetermineAddChange(CSharpDirective directive) var result = tokenizer.ParseNextToken(); var leadingTrivia = result.Token.LeadingTrivia; - // If there is a comment at the top of the file, we add the directive after it + // If there is a comment or #! at the top of the file, we add the directive after it // (the comment might be a license which should always stay at the top). int insertAfterIndex = -1; int trailingNewLines = 0; @@ -161,6 +170,11 @@ private TextChange DetermineAddChange(CSharpDirective directive) } break; + case SyntaxKind.ShebangDirectiveTrivia: + trailingNewLines = 1; // shebang trivia has one newline embedded in its structure + insertAfterIndex = i; + break; + case SyntaxKind.EndOfLineTrivia: if (insertAfterIndex >= 0) { diff --git a/src/sdk/src/Cli/dotnet/Commands/Run/RunCommand.cs b/src/sdk/src/Cli/dotnet/Commands/Run/RunCommand.cs index 33ec7b5e321..635566bf07b 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Run/RunCommand.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Run/RunCommand.cs @@ -397,7 +397,7 @@ internal ICommand GetTargetCommand(Func? pro // So we can skip project evaluation to continue the optimized path. Debug.Assert(EntryPointFileFullPath is not null); Reporter.Verbose.WriteLine("Getting target command: for csc-built program."); - return CreateCommandForCscBuiltProgram(EntryPointFileFullPath); + return CreateCommandForCscBuiltProgram(EntryPointFileFullPath, ApplicationArgs); } Reporter.Verbose.WriteLine("Getting target command: evaluating project."); @@ -463,11 +463,11 @@ static void SetRootVariableName(ICommand command, string runtimeIdentifier, stri } } - static ICommand CreateCommandForCscBuiltProgram(string entryPointFileFullPath) + static ICommand CreateCommandForCscBuiltProgram(string entryPointFileFullPath, string[] args) { var artifactsPath = VirtualProjectBuildingCommand.GetArtifactsPath(entryPointFileFullPath); var exePath = Path.Join(artifactsPath, "bin", "debug", Path.GetFileNameWithoutExtension(entryPointFileFullPath) + FileNameSuffixes.CurrentPlatform.Exe); - var commandSpec = new CommandSpec(path: exePath, args: null); + var commandSpec = new CommandSpec(path: exePath, args: ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(args)); var command = CommandFactoryUsingResolver.Create(commandSpec) .WorkingDirectory(Path.GetDirectoryName(entryPointFileFullPath)); @@ -483,7 +483,9 @@ static ICommand CreateCommandForCscBuiltProgram(string entryPointFileFullPath) static void InvokeRunArgumentsTarget(ProjectInstance project, bool noBuild, FacadeLogger? binaryLogger, MSBuildArgs buildArgs) { List loggersForBuild = [ - TerminalLogger.CreateTerminalOrConsoleLogger([$"--verbosity:{LoggerVerbosity.Quiet.ToString().ToLowerInvariant()}", ..buildArgs.OtherMSBuildArgs]) + CommonRunHelpers.GetConsoleLogger( + buildArgs.CloneWithExplicitArgs([$"--verbosity:{LoggerVerbosity.Quiet.ToString().ToLowerInvariant()}", ..buildArgs.OtherMSBuildArgs]) + ) ]; if (binaryLogger is not null) { @@ -824,11 +826,11 @@ private void SendProjectBasedTelemetry(ProjectLaunchSettingsModel? launchSetting { Debug.Assert(ProjectFileFullPath != null); var projectIdentifier = RunTelemetry.GetProjectBasedIdentifier(ProjectFileFullPath, GetRepositoryRoot(), Sha256Hasher.Hash); - + // Get package and project reference counts for project-based apps int packageReferenceCount = 0; int projectReferenceCount = 0; - + // Try to get project information for telemetry if we built the project if (ShouldBuild) { @@ -837,10 +839,10 @@ private void SendProjectBasedTelemetry(ProjectLaunchSettingsModel? launchSetting var globalProperties = MSBuildArgs.GlobalProperties?.ToDictionary() ?? new Dictionary(StringComparer.OrdinalIgnoreCase); globalProperties[Constants.EnableDefaultItems] = "false"; globalProperties[Constants.MSBuildExtensionsPath] = AppContext.BaseDirectory; - + using var collection = new ProjectCollection(globalProperties: globalProperties); var project = collection.LoadProject(ProjectFileFullPath).CreateProjectInstance(); - + packageReferenceCount = RunTelemetry.CountPackageReferences(project); projectReferenceCount = RunTelemetry.CountProjectReferences(project); } @@ -869,10 +871,10 @@ private void SendProjectBasedTelemetry(ProjectLaunchSettingsModel? launchSetting { try { - var currentDir = ProjectFileFullPath != null + var currentDir = ProjectFileFullPath != null ? Path.GetDirectoryName(ProjectFileFullPath) : Directory.GetCurrentDirectory(); - + while (currentDir != null) { if (Directory.Exists(Path.Combine(currentDir, ".git"))) @@ -886,7 +888,7 @@ private void SendProjectBasedTelemetry(ProjectLaunchSettingsModel? launchSetting { // Ignore errors when trying to find repo root } - + return null; } } diff --git a/src/sdk/src/Cli/dotnet/Commands/Run/RunTelemetry.cs b/src/sdk/src/Cli/dotnet/Commands/Run/RunTelemetry.cs index 35e13b2d3fd..1e58bdd27c0 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Run/RunTelemetry.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Run/RunTelemetry.cs @@ -47,9 +47,13 @@ public static void TrackRunEvent( { ["app_type"] = isFileBased ? "file_based" : "project_based", ["project_id"] = projectIdentifier, - ["sdk_count"] = sdkCount.ToString(), - ["package_reference_count"] = packageReferenceCount.ToString(), - ["project_reference_count"] = projectReferenceCount.ToString(), + }; + + var measurements = new Dictionary + { + ["sdk_count"] = sdkCount, + ["package_reference_count"] = packageReferenceCount, + ["project_reference_count"] = projectReferenceCount, }; // Launch profile telemetry @@ -75,7 +79,7 @@ public static void TrackRunEvent( // File-based app specific telemetry if (isFileBased) { - properties["additional_properties_count"] = additionalPropertiesCount.ToString(); + measurements["additional_properties_count"] = additionalPropertiesCount; if (usedMSBuild.HasValue) { properties["used_msbuild"] = usedMSBuild.Value ? "true" : "false"; @@ -86,7 +90,7 @@ public static void TrackRunEvent( } } - TelemetryEventEntry.TrackEvent(RunEventName, properties, measurements: null); + TelemetryEventEntry.TrackEvent(RunEventName, properties, measurements); } /// @@ -234,4 +238,4 @@ private static bool IsDefaultProfile(string? profileName) // The default profile name at this point is "(Default)" return profileName.Equals("(Default)", StringComparison.OrdinalIgnoreCase); } -} \ No newline at end of file +} diff --git a/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs b/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs index 632fc6f8654..6b99feedd1a 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs @@ -75,13 +75,14 @@ internal sealed class VirtualProjectBuildingCommand : CommandBase /// /// Kept in sync with the default dotnet new console project file (enforced by DotnetProjectAddTests.SameAsTemplate). /// - private static readonly FrozenDictionary s_defaultProperties = FrozenDictionary.Create(StringComparer.OrdinalIgnoreCase, + public static readonly FrozenDictionary DefaultProperties = FrozenDictionary.Create(StringComparer.OrdinalIgnoreCase, [ new("OutputType", "Exe"), new("TargetFramework", $"net{TargetFrameworkVersion}"), new("ImplicitUsings", "enable"), new("Nullable", "enable"), new("PublishAot", "true"), + new("PackAsTool", "true"), ]); /// @@ -189,7 +190,7 @@ public override int Execute() var verbosity = MSBuildArgs.Verbosity ?? MSBuildForwardingAppWithoutLogging.DefaultVerbosity; var consoleLogger = minimizeStdOut ? new SimpleErrorLogger() - : TerminalLogger.CreateTerminalOrConsoleLogger([$"--verbosity:{verbosity}", .. MSBuildArgs.OtherMSBuildArgs]); + : CommonRunHelpers.GetConsoleLogger(MSBuildArgs.CloneWithExplicitArgs([$"--verbosity:{verbosity}", .. MSBuildArgs.OtherMSBuildArgs])); var binaryLogger = GetBinaryLogger(MSBuildArgs.OtherMSBuildArgs); CacheInfo? cache = null; @@ -355,9 +356,16 @@ public override int Execute() // Cache run info (to avoid re-evaluating the project instance). cache.CurrentEntry.Run = RunProperties.FromProject(buildRequest.ProjectInstance); - TryCacheCscArguments(cache, buildResult, buildRequest.ProjectInstance); + if (!MSBuildUtilities.ConvertStringToBool(buildRequest.ProjectInstance.GetPropertyValue(FileBasedProgramCanSkipMSBuild), defaultValue: true)) + { + Reporter.Verbose.WriteLine($"Not saving cache because there is an opt-out via MSBuild property {FileBasedProgramCanSkipMSBuild}."); + } + else + { + CacheCscArguments(cache, buildResult); - MarkBuildSuccess(cache); + MarkBuildSuccess(cache); + } } projectInstance = buildRequest.ProjectInstance; @@ -444,14 +452,8 @@ static Action> AddRestoreGlobalProperties(ReadOnlyDi return null; } - void TryCacheCscArguments(CacheInfo cache, BuildResult result, ProjectInstance projectInstance) + void CacheCscArguments(CacheInfo cache, BuildResult result) { - if (!MSBuildUtilities.ConvertStringToBool(projectInstance.GetPropertyValue(FileBasedProgramCanSkipMSBuild), defaultValue: true)) - { - Reporter.Verbose.WriteLine($"Not saving CSC arguments because there is an opt-out via MSBuild property {FileBasedProgramCanSkipMSBuild}."); - return; - } - // We cannot reuse CSC arguments from previous run and skip MSBuild if there are project references // because we cannot easily detect whether any referenced projects have changed. if (Directives.Any(static d => d is CSharpDirective.Project)) @@ -1139,8 +1141,12 @@ public static void WriteProjectFile( string? targetFilePath = null, string? artifactsPath = null, bool includeRuntimeConfigInformation = true, - string? userSecretsId = null) + string? userSecretsId = null, + IEnumerable? excludeDefaultProperties = null) { + Debug.Assert(userSecretsId == null || !isVirtualProject); + Debug.Assert(excludeDefaultProperties == null || !isVirtualProject); + int processedDirectives = 0; var sdkDirectives = directives.OfType(); @@ -1179,6 +1185,20 @@ public static void WriteProjectFile( artifacts/$(MSBuildProjectName) artifacts/$(MSBuildProjectName) true + false + true + """); + + // Write default properties before importing SDKs so they can be overridden by SDKs + // (and implicit build files which are imported by the default .NET SDK). + foreach (var (name, value) in DefaultProperties) + { + writer.WriteLine($""" + <{name}>{EscapeValue(value)} + """); + } + + writer.WriteLine($""" @@ -1245,34 +1265,30 @@ public static void WriteProjectFile( """); // First write the default properties except those specified by the user. - var customPropertyNames = propertyDirectives.Select(d => d.Name).ToHashSet(StringComparer.OrdinalIgnoreCase); - foreach (var (name, value) in s_defaultProperties) + if (!isVirtualProject) { - if (!customPropertyNames.Contains(name)) + var customPropertyNames = propertyDirectives + .Select(static d => d.Name) + .Concat(excludeDefaultProperties ?? []) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + foreach (var (name, value) in DefaultProperties) + { + if (!customPropertyNames.Contains(name)) + { + writer.WriteLine($""" + <{name}>{EscapeValue(value)} + """); + } + } + + if (userSecretsId != null && !customPropertyNames.Contains("UserSecretsId")) { writer.WriteLine($""" - <{name}>{EscapeValue(value)} + {EscapeValue(userSecretsId)} """); } } - if (userSecretsId != null && !customPropertyNames.Contains("UserSecretsId")) - { - writer.WriteLine($""" - {EscapeValue(userSecretsId)} - """); - } - - // Write virtual-only properties. - if (isVirtualProject) - { - writer.WriteLine(""" - false - true - false - """); - } - // Write custom properties. foreach (var property in propertyDirectives) { @@ -1287,6 +1303,7 @@ public static void WriteProjectFile( if (isVirtualProject) { writer.WriteLine(""" + false $(Features);FileBasedProgram """); } @@ -1488,8 +1505,15 @@ public static ImmutableArray FindDirectives(SourceFile sourceFi Diagnostics = diagnostics, SourceFile = sourceFile, DirectiveKind = name.ToString(), - DirectiveText = value.ToString() + DirectiveText = value.ToString(), }; + + // Block quotes now so we can later support quoted values without a breaking change. https://github.com/dotnet/sdk/issues/49367 + if (value.Contains('"')) + { + diagnostics.AddError(sourceFile, context.Info.Span, CliCommandStrings.QuoteInDirective); + } + if (CSharpDirective.Parse(context) is { } directive) { // If the directive is already present, report an error. @@ -1885,7 +1909,11 @@ public sealed class Project(in ParseInfo info) : Named(info) if (Directory.Exists(resolvedProjectPath)) { var fullFilePath = MsbuildProject.GetProjectFileFromDirectory(resolvedProjectPath).FullName; - directiveText = Path.GetRelativePath(relativeTo: sourceDirectory, fullFilePath); + + // Keep a relative path only if the original directive was a relative path. + directiveText = Path.IsPathFullyQualified(directiveText) + ? fullFilePath + : Path.GetRelativePath(relativeTo: sourceDirectory, fullFilePath); } else if (!File.Exists(resolvedProjectPath)) { @@ -1903,6 +1931,11 @@ public sealed class Project(in ParseInfo info) : Named(info) }; } + public Project WithName(string name) + { + return new Project(Info) { Name = name }; + } + public override string ToString() => $"#:project {Name}"; } } diff --git a/src/sdk/src/Cli/dotnet/Commands/Test/MTP/Terminal/HumanReadableDurationFormatter.cs b/src/sdk/src/Cli/dotnet/Commands/Test/MTP/Terminal/HumanReadableDurationFormatter.cs index 559af6b7784..30416634132 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Test/MTP/Terminal/HumanReadableDurationFormatter.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Test/MTP/Terminal/HumanReadableDurationFormatter.cs @@ -16,6 +16,7 @@ public static void Append(ITerminal terminal, TimeSpan duration, bool wrapInPare terminal.Append('('); } + // TODO: Do these abbrevations (d for days, h for hours, etc) need to be localized? if (duration.Days > 0) { terminal.Append($"{duration.Days}d"); diff --git a/src/sdk/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs b/src/sdk/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs index 3e320fa8a06..22929d8dfb7 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs @@ -280,13 +280,13 @@ private void AppendTestRunSummary(ITerminal terminal, int? exitCode) bool colorizePassed = passed > 0 && _buildErrorsCount == 0 && failed == 0 && error == 0; bool colorizeSkipped = skipped > 0 && skipped == total && _buildErrorsCount == 0 && failed == 0 && error == 0; - string errorText = $"{SingleIndentation}error: {error}"; - string totalText = $"{SingleIndentation}total: {total}"; - string retriedText = $" (+{retried} retried)"; - string failedText = $"{SingleIndentation}failed: {failed}"; - string passedText = $"{SingleIndentation}succeeded: {passed}"; - string skippedText = $"{SingleIndentation}skipped: {skipped}"; - string durationText = $"{SingleIndentation}duration: "; + string errorText = $"{SingleIndentation}{CliCommandStrings.ErrorColon} {error}"; + string totalText = $"{SingleIndentation}{CliCommandStrings.TotalColon} {total}"; + string retriedText = $" (+{retried} {CliCommandStrings.Retried})"; + string failedText = $"{SingleIndentation}{CliCommandStrings.FailedColon} {failed}"; + string passedText = $"{SingleIndentation}{CliCommandStrings.SucceededColon} {passed}"; + string skippedText = $"{SingleIndentation}{CliCommandStrings.SkippedColon} {skipped}"; + string durationText = $"{SingleIndentation}{CliCommandStrings.DurationColon} "; if (error > 0) { diff --git a/src/sdk/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs b/src/sdk/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs index fc181b155db..16ca1bb218e 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs @@ -20,6 +20,7 @@ internal sealed class TestApplication( TerminalTestReporter output, Action onHelpRequested) : IDisposable { + private readonly Lock _requestLock = new(); private readonly BuildOptions _buildOptions = buildOptions; private readonly Action _onHelpRequested = onHelpRequested; private readonly TestApplicationHandler _handler = new(output, module, testOptions); @@ -199,63 +200,69 @@ private async Task WaitConnectionAsync(CancellationToken token) private Task OnRequest(NamedPipeServer server, IRequest request) { - try + // We need to lock as we might be called concurrently when test app child processes all communicate with us. + // For example, in a case of a sharding extension, we could get test result messages concurrently. + // To be the most safe, we lock the whole OnRequest. + lock (_requestLock) { - switch (request) + try { - case HandshakeMessage handshakeMessage: - _handshakes.Add(server, handshakeMessage); - string negotiatedVersion = GetSupportedProtocolVersion(handshakeMessage); - OnHandshakeMessage(handshakeMessage, negotiatedVersion.Length > 0); - return Task.FromResult((IResponse)CreateHandshakeMessage(negotiatedVersion)); - - case CommandLineOptionMessages commandLineOptionMessages: - OnCommandLineOptionMessages(commandLineOptionMessages); - break; - - case DiscoveredTestMessages discoveredTestMessages: - OnDiscoveredTestMessages(discoveredTestMessages); - break; - - case TestResultMessages testResultMessages: - OnTestResultMessages(testResultMessages); - break; - - case FileArtifactMessages fileArtifactMessages: - OnFileArtifactMessages(fileArtifactMessages); - break; - - case TestSessionEvent sessionEvent: - OnSessionEvent(sessionEvent); - break; - - // If we don't recognize the message, log and skip it - case UnknownMessage unknownMessage: - Logger.LogTrace($"Request '{request.GetType()}' with Serializer ID = {unknownMessage.SerializerId} is unsupported."); - return Task.FromResult((IResponse)VoidResponse.CachedInstance); - - default: - // If it doesn't match any of the above, throw an exception - throw new NotSupportedException(string.Format(CliCommandStrings.CmdUnsupportedMessageRequestTypeException, request.GetType())); + switch (request) + { + case HandshakeMessage handshakeMessage: + _handshakes.Add(server, handshakeMessage); + string negotiatedVersion = GetSupportedProtocolVersion(handshakeMessage); + OnHandshakeMessage(handshakeMessage, negotiatedVersion.Length > 0); + return Task.FromResult((IResponse)CreateHandshakeMessage(negotiatedVersion)); + + case CommandLineOptionMessages commandLineOptionMessages: + OnCommandLineOptionMessages(commandLineOptionMessages); + break; + + case DiscoveredTestMessages discoveredTestMessages: + OnDiscoveredTestMessages(discoveredTestMessages); + break; + + case TestResultMessages testResultMessages: + OnTestResultMessages(testResultMessages); + break; + + case FileArtifactMessages fileArtifactMessages: + OnFileArtifactMessages(fileArtifactMessages); + break; + + case TestSessionEvent sessionEvent: + OnSessionEvent(sessionEvent); + break; + + // If we don't recognize the message, log and skip it + case UnknownMessage unknownMessage: + Logger.LogTrace($"Request '{request.GetType()}' with Serializer ID = {unknownMessage.SerializerId} is unsupported."); + return Task.FromResult((IResponse)VoidResponse.CachedInstance); + + default: + // If it doesn't match any of the above, throw an exception + throw new NotSupportedException(string.Format(CliCommandStrings.CmdUnsupportedMessageRequestTypeException, request.GetType())); + } + } + catch (Exception ex) + { + // BE CAREFUL: + // When handling some of the messages, we may throw an exception in unexpected state. + // (e.g, OnSessionEvent may throw if we receive TestSessionEnd without TestSessionStart). + // (or if we receive help-related messages when not in help mode) + // In that case, we FailFast. + // The lack of FailFast *might* have unintended consequences, such as breaking the internal loop of pipe server. + // In that case, maybe MTP app will continue waiting for response, but we don't send the response and are waiting for + // MTP app process exit (which doesn't happen). + // So, we explicitly FailFast here. + string exAsString = ex.ToString(); + Logger.LogTrace(exAsString); + Environment.FailFast(exAsString); } - } - catch (Exception ex) - { - // BE CAREFUL: - // When handling some of the messages, we may throw an exception in unexpected state. - // (e.g, OnSessionEvent may throw if we receive TestSessionEnd without TestSessionStart). - // (or if we receive help-related messages when not in help mode) - // In that case, we FailFast. - // The lack of FailFast *might* have unintended consequences, such as breaking the internal loop of pipe server. - // In that case, maybe MTP app will continue waiting for response, but we don't send the response and are waiting for - // MTP app process exit (which doesn't happen). - // So, we explicitly FailFast here. - string exAsString = ex.ToString(); - Logger.LogTrace(exAsString); - Environment.FailFast(exAsString); - } - return Task.FromResult((IResponse)VoidResponse.CachedInstance); + return Task.FromResult((IResponse)VoidResponse.CachedInstance); + } } private static string GetSupportedProtocolVersion(HandshakeMessage handshakeMessage) diff --git a/src/sdk/src/Cli/dotnet/Commands/Test/TestCommandParser.cs b/src/sdk/src/Cli/dotnet/Commands/Test/TestCommandParser.cs index 0fb00c0de94..db52e8975ed 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Test/TestCommandParser.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Test/TestCommandParser.cs @@ -5,7 +5,6 @@ using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.DotNet.Cli.Extensions; -using Microsoft.DotNet.Cli.Utils; using Command = System.CommandLine.Command; namespace Microsoft.DotNet.Cli.Commands.Test; @@ -234,7 +233,7 @@ private static Command ConstructCommand() private static Command GetTestingPlatformCliCommand() { - var command = new MicrosoftTestingPlatformTestCommand("test", CliCommandStrings.DotnetTestCommand); + var command = new MicrosoftTestingPlatformTestCommand("test", CliCommandStrings.DotnetTestCommandMTPDescription); command.SetAction(parseResult => command.Run(parseResult)); command.Options.Add(MicrosoftTestingPlatformOptions.ProjectOption); command.Options.Add(MicrosoftTestingPlatformOptions.SolutionOption); @@ -268,7 +267,7 @@ private static Command GetTestingPlatformCliCommand() private static Command GetVSTestCliCommand() { - DocumentedCommand command = new("test", DocsLink, CliCommandStrings.TestAppFullName) + DocumentedCommand command = new("test", DocsLink, CliCommandStrings.DotnetTestCommandVSTestDescription) { TreatUnmatchedTokensAsErrors = false }; diff --git a/src/sdk/src/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs b/src/sdk/src/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs index cf082e5e052..a17cc0031e1 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Frozen; using System.CommandLine; using System.Diagnostics.CodeAnalysis; using System.Runtime.Versioning; @@ -298,11 +297,16 @@ internal static int RunArtifactPostProcessingIfNeeded(string testSessionCorrelat private static bool ContainsBuiltTestSources(string[] args) { - foreach (string arg in args) + for (int i = 0; i < args.Length; i++) { - if (!arg.StartsWith("-") && - (arg.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) || arg.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))) + string arg = args[i]; + if (arg.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) || arg.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)) { + var previousArg = i > 0 ? args[i - 1] : null; + if (previousArg != null && CommonOptions.PropertiesOption.Aliases.Contains(previousArg)) + { + return false; + } return true; } } diff --git a/src/sdk/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommandParser.cs b/src/sdk/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommandParser.cs index f2c0109fe9f..009b270947a 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommandParser.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommandParser.cs @@ -10,7 +10,7 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Install; internal static class ToolInstallCommandParser { - public static readonly Argument PackageIdentityArgument = CommonArguments.RequiredPackageIdentityArgument(); + public static readonly Argument PackageIdentityArgument = CommonArguments.RequiredPackageIdentityArgument("dotnetsay", "2.1.7"); public static readonly Option VersionOption = new("--version") { diff --git a/src/sdk/src/Cli/dotnet/Commands/Tool/Install/ToolInstallGlobalOrToolPathCommand.cs b/src/sdk/src/Cli/dotnet/Commands/Tool/Install/ToolInstallGlobalOrToolPathCommand.cs index 0a23fad4391..c465e20372e 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Tool/Install/ToolInstallGlobalOrToolPathCommand.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Tool/Install/ToolInstallGlobalOrToolPathCommand.cs @@ -96,7 +96,22 @@ public ToolInstallGlobalOrToolPathCommand( NoCache: parseResult.GetValue(ToolCommandRestorePassThroughOptions.NoCacheOption) || parseResult.GetValue(ToolCommandRestorePassThroughOptions.NoHttpCacheOption), IgnoreFailedSources: parseResult.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption), Interactive: parseResult.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption)); - nugetPackageDownloader ??= new NuGetPackageDownloader.NuGetPackageDownloader(tempDir, verboseLogger: new NullLogger(), restoreActionConfig: restoreActionConfig, verbosityOptions: _verbosity, verifySignatures: verifySignatures ?? true); + nugetPackageDownloader ??= new NuGetPackageDownloader.NuGetPackageDownloader(tempDir, verboseLogger: new NullLogger(), restoreActionConfig: restoreActionConfig, verbosityOptions: _verbosity, verifySignatures: verifySignatures ?? true, shouldUsePackageSourceMapping: true, currentWorkingDirectory: _currentWorkingDirectory); + + // Perform HTTP source validation early to ensure compatibility with .NET 9 requirements + if (_packageId != null) + { + var packageSourceLocationForValidation = new PackageSourceLocation( + nugetConfig: GetConfigFile(), + additionalSourceFeeds: _addSource, + basePath: _currentWorkingDirectory); + + if (nugetPackageDownloader is NuGetPackageDownloader.NuGetPackageDownloader concreteDownloader) + { + concreteDownloader.LoadNuGetSources((PackageId)_packageId, packageSourceLocationForValidation); + } + } + _shellShimTemplateFinder = new ShellShimTemplateFinder(nugetPackageDownloader, tempDir, packageSourceLocation); _store = store; diff --git a/src/sdk/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateCommandParser.cs b/src/sdk/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateCommandParser.cs index 1bbb466a6af..f29fce2f708 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateCommandParser.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateCommandParser.cs @@ -9,7 +9,7 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Update; internal static class ToolUpdateCommandParser { - public static readonly Argument PackageIdentityArgument = CommonArguments.OptionalPackageIdentityArgument(); + public static readonly Argument PackageIdentityArgument = CommonArguments.OptionalPackageIdentityArgument("dotnetsay", "2.1.7"); public static readonly Option UpdateAllOption = ToolAppliedOption.UpdateAllOption; diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index a122873dc94..10a84c76b1a 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -186,7 +186,7 @@ Prohledané cesty: „{1}“, „{2}“. Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + Některé direktivy nelze převést. Spuštěním souboru zobrazíte všechny chyby kompilace. Zadejte „--force“, pokud chcete přesto provést převod. {Locked="--force"} @@ -585,7 +585,7 @@ Jedná se o ekvivalent odstranění project.assets.json. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + Určuje minimální počet testů, jejichž spuštění se očekává. @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + Soubor global.json definuje, že spouštěč testů bude Microsoft.Testing.Platform. Tento spouštěč testů musí používat všechny projekty. +Následující testovací projekty používají spouštěč testů VSTest: {0} -See https://aka.ms/dotnet-test/mtp for more information. +Další informace najdete na https://aka.ms/dotnet-test/mtp. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + chyba Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. Zjišťování testů z - - .NET Test Command - Testovací příkaz .NET - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Podporované verze protokolů odesílané Microsoft.Testing.Platform jsou {0}. Sada SDK podporuje {1}, což není kompatibilní. Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + Byla přijata hodnota ExecutionId {0} pro zprávu {1}, zatímco ExecutionId přijaté zprávy metodou handshake bylo {2}. {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + Chyba při rušení serveru NamedPipeServer odpovídajícího zprávě metodou handshake: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + Při rušení serveru NamedPipeServer došlo k chybě a nebyla nalezena žádná zpráva metodou handshake. 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + Příkaz dotnet neočekávaně obdržel z pojmenovaného kanálu dotnet test méně než 4 bajty. 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + Příkaz dotnet neočekávaně obdržel překrývající se zprávy z pojmenovaného kanálu dotnet test. @@ -1228,14 +1233,24 @@ Nastavte odlišné názvy profilů. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + Duplicitní direktivy nejsou podporovány: {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + Při spuštění testovacího modulu s příkazem RunCommand {0} a argumenty RunArguments {1} došlo k následující výjimce: {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Nastavte odlišné názvy profilů. Nepovedlo se aktualizovat manifest reklamy {0}: {1}. + + failed: + failed: + + failed selhalo @@ -1568,12 +1588,12 @@ Nastavte odlišné názvy profilů. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + Metoda {0} nebyla úspěšně ukončena. The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + Direktiva by měla obsahovat název bez speciálních znaků a volitelnou hodnotu oddělenou znakem {1}, například #:{0} Název{1}Hodnota. {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Nastavte odlišné názvy profilů. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + Direktiva #:project je neplatná: {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ Nástroj {1} (verze {2}) se úspěšně nainstaloval. Do souboru manifestu {3} s A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + Byla přijata nová zpráva metodou handshake {0} pro testovací aplikaci, který neodpovídá předchozí zprávě metodou handshake {1}. Missing name of '{0}'. - Missing name of '{0}'. + Chybí název pro: {0}. {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + Byla přijata počáteční událost testovací relace bez odpovídajícího konce testovací relace. @@ -2502,12 +2522,12 @@ Nástroj {1} (verze {2}) se úspěšně nainstaloval. Do souboru manifestu {3} s Invalid property name: {0} - Invalid property name: {0} + Neplatný název vlastnosti: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + Direktiva property musí mít dvě části oddělené znakem =, například #:property PropertyName=PropertyValue. {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. Ve výchozím nastavení je publikována aplikace závislá na architektuře. + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Vypne buildovací server Razor. @@ -2672,6 +2697,11 @@ Ve výchozím nastavení je publikována aplikace závislá na architektuře.Nástroj {0} (verze {1}) se obnovil. Dostupné příkazy: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). Posune se na vyšší verzi architektury (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). @@ -2951,6 +2981,11 @@ Cílem projektu je více architektur. Pomocí parametru {0} určete, která arch Vynechá vytvoření souborů symbolů, které lze použít k profilaci optimalizovaných sestavení. + + skipped: + skipped: + + skipped vynecháno @@ -3048,7 +3083,7 @@ Cílem projektu je více architektur. Pomocí parametru {0} určete, která arch Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + Statické obnovení grafu se pro souborové aplikace nepodporuje. Odeberte #:property. {Locked="#:property"} @@ -3086,6 +3121,11 @@ Cílem projektu je více architektur. Pomocí parametru {0} určete, která arch Cílový modul runtime pro uložení balíčků + + succeeded: + succeeded: + + Summary Souhrn @@ -3101,11 +3141,6 @@ Cílem projektu je více architektur. Pomocí parametru {0} určete, která arch Zadejte dočasný adresář pro tento příkaz, který se má stáhnout a extrahujte balíčky NuGet (musí být zabezpečené). - - .NET Test Driver - Testovací ovladač .NET - - + + total: + total: + + try {0} {0} pokus @@ -3559,22 +3599,22 @@ příkazu „dotnet tool list“. An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + Byla obdržena neočekávaná zpráva týkající se nápovědy, když nebyl použit parametr --help. A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + V režimu nápovědy byla přijata zpráva typu {0}, což není očekáváno. A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + Zpráva typu {0} byla přijata předtím, než jsme obdrželi jakékoli zprávy metodou handshake, což je neočekávané. A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + Byla přijata koncová událost testovací relace bez odpovídajícího začátku testovací relace. @@ -3594,7 +3634,7 @@ příkazu „dotnet tool list“. Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + Nerozpoznaná direktiva {0}. {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index d9da0a1e0d4..70630b7a74b 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -186,7 +186,7 @@ Durchsuchte Pfade: "{1}", "{2}". Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + Einige Anweisungen können nicht konvertiert werden. Führen Sie die Datei aus, um alle Kompilierungsfehler anzuzeigen. Geben Sie „--force“ an, um das Umwandeln trotzdem auszuführen. {Locked="--force"} @@ -585,7 +585,7 @@ Dies entspricht dem Löschen von "project.assets.json". Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + Gibt die Mindestanzahl von Tests an, die ausgeführt werden sollen. @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + global.json definiert den Testausführer als Microsoft.Testing.Platform. Alle Projekte müssen diesen Testausführer verwenden. +Die folgenden Testprojekte verwenden den VSTest-Testausführer: {0} -See https://aka.ms/dotnet-test/mtp for more information. +Weitere Informationen finden Sie unter https://aka.ms/dotnet-test/mtp. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + Fehler Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. Tests ermitteln aus - - .NET Test Command - Testbefehl .NET - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Unterstützte Protokollversionen, die von Microsoft.Testing.Platform gesendet werden, sind „{0}“. Das SDK unterstützt „{1}“, was inkompatibel ist. Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + „ExecutionId“ des Werts „{0}“ für die Nachricht „{1}“ wurde empfangen, während die „ExecutionId“ der Handshakenachricht „{2}“ war. {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + Fehler beim Löschen von „NamedPipeServer“, der dem Handshake entspricht: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + Fehler beim Freigeben von „NamedPipeServer“, und es wurde kein Handshake gefunden. 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + „dotnet“ hat unerwartet weniger als 4 Bytes von der Named Pipe „dotnet test“ empfangen. 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + „dotnet“ hat unerwartet überlappende Nachrichten von der Named Pipe „dotnet test“ empfangen. @@ -1228,14 +1233,24 @@ Erstellen Sie eindeutige Profilnamen. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + Doppelte Anweisungen werden nicht unterstützt: {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + Beim Ausführen des Testmoduls mit RunCommand „{0}“ und RunArguments „{1}“ ist folgende Ausnahme aufgetreten: {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Erstellen Sie eindeutige Profilnamen. Fehler beim Aktualisieren des Ankündigungsmanifests "{0}": {1}. + + failed: + failed: + + failed fehlerhaft @@ -1568,12 +1588,12 @@ Erstellen Sie eindeutige Profilnamen. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + Die Methode "{0}" wurde nicht erfolgreich beendet The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + Die Anweisung sollte einen Namen ohne Sonderzeichen und einen optionalen Wert enthalten, die durch „{1}“ getrennt sind, wie „#:{0} Name{1}Wert“. {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Erstellen Sie eindeutige Profilnamen. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + Die Anweisung „#:p roject“ ist ungültig: {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ Das Tool "{1}" (Version {2}) wurde erfolgreich installiert. Der Eintrag wird der A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + Für die Testanwendung wurde ein neuer Handshake „{0}“ empfangen, der nicht mit dem vorherigen Handshake „{1}“ übereinstimmt. Missing name of '{0}'. - Missing name of '{0}'. + Fehlender Name der Anweisung „{0}“. {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + Ein Testsitzungs-Startereignis wurde ohne entsprechendes Testsitzungs-Ende empfangen. @@ -2502,12 +2522,12 @@ Das Tool "{1}" (Version {2}) wurde erfolgreich installiert. Der Eintrag wird der Invalid property name: {0} - Invalid property name: {0} + Ungültiger Eigenschaftenname: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + Die Eigenschaftsanweisung muss zwei durch „=“ getrennte Teile aufweisen, z. B. „#:property PropertyName=PropertyValue“. {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. Standardmäßig wird eine Framework-abhängige Anwendung veröffentlicht. + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Hiermit wird der Razor-Buildserver heruntergefahren. @@ -2672,6 +2697,11 @@ Standardmäßig wird eine Framework-abhängige Anwendung veröffentlicht.Das Tool "{0}" (Version {1}) wurde wiederhergestellt. Verfügbare Befehle: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). Rollforward zu Frameworkversion (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). @@ -2951,6 +2981,11 @@ Ihr Projekt verwendet mehrere Zielframeworks. Geben Sie über "{0}" an, welches Hiermit wird die Erstellung von Symboldateien übersprungen, die für die Profilerstellung der optimierten Assemblys verwendet werden können. + + skipped: + skipped: + + skipped übersprungen @@ -3048,7 +3083,7 @@ Ihr Projekt verwendet mehrere Zielframeworks. Geben Sie über "{0}" an, welches Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + Die Statische Graphwiederherstellung wird für dateibasierte Apps nicht unterstützt. Entfernen Sie '#:property'. {Locked="#:property"} @@ -3086,6 +3121,11 @@ Ihr Projekt verwendet mehrere Zielframeworks. Geben Sie über "{0}" an, welches Die Zielruntime zum Speichern von Paketen. + + succeeded: + succeeded: + + Summary Zusammenfassung @@ -3101,11 +3141,6 @@ Ihr Projekt verwendet mehrere Zielframeworks. Geben Sie über "{0}" an, welches Geben Sie ein temporäres Verzeichnis für diesen Befehl zum Herunterladen und Extrahieren von NuGet-Paketen an (muss sicher sein). - - .NET Test Driver - .NET-Testtreiber - - + + total: + total: + + try {0} {0} testen @@ -3559,22 +3599,22 @@ und die zugehörigen Paket-IDs für installierte Tools über den Befehl An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + Eine unerwartete hilfebezogene Nachricht wurde empfangen, obwohl „--help“ nicht verwendet wurde. A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + Eine Nachricht vom Typ „{0}“ wurde im Hilfemodus empfangen, was nicht erwartet wird. A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + Eine Nachricht vom Typ „{0}“ wurde empfangen, bevor ein Handshake erfolgte, was unerwartet ist. A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + Ein Testsitzungs-Endereignis wurde ohne einen entsprechenden Testsitzungsstart empfangen. @@ -3594,7 +3634,7 @@ und die zugehörigen Paket-IDs für installierte Tools über den Befehl Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + Unbekannte Anweisung „{0}“. {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index 0d4fcd802d0..84d3025e048 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -186,7 +186,7 @@ Rutas de acceso buscadas: "{1}", "{2}". Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + Algunas directivas no se pueden convertir. Ejecute el archivo para ver todos los errores de compilación. Especifique "--force" para convertir de todos modos. {Locked="--force"} @@ -585,7 +585,7 @@ Esta acción es equivalente a eliminar project.assets.json. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + Especifica el número mínimo de pruebas que se espera que se ejecuten. @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + global.json define el ejecutor de pruebas para que sea Microsoft.Testing.Platform. Todos los proyectos deben usar ese ejecutor de pruebas. +Los siguientes proyectos de prueba usan el ejecutor de pruebas de VSTest: {0} -See https://aka.ms/dotnet-test/mtp for more information. +Consulte https://aka.ms/dotnet-test/mtp para obtener más información. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + error Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. Detección de pruebas de - - .NET Test Command - Comando de prueba de .NET - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Las versiones de protocolo admitidas enviadas por Microsoft.Testing.Platform son "{0}". El SDK admite "{1}", que es incompatible. Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + Se recibió un "ExecutionId" con valor "{0}" para el mensaje "{1}", mientras que el "ExecutionId" recibido en el mensaje de protocolo de enlace era "{2}". {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + Error al liberar "NamedPipeServer" correspondiente al protocolo de enlace: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + Error al liberar "NamedPipeServer" y no se encontró ningún protocolo de enlace. 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + "dotnet" recibió inesperadamente menos de 4 bytes de la canalización con nombre "dotnet test". 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + "dotnet" recibió inesperadamente mensajes superpuestos desde la canalización con nombre "dotnet test". @@ -1228,14 +1233,24 @@ Defina nombres de perfiles distintos. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + No se admiten directivas duplicadas: {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + Se produjo la siguiente excepción al ejecutar el módulo de prueba con RunCommand "{0}" y RunArguments "{1}": {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Defina nombres de perfiles distintos. No se pudo actualizar el manifiesto publicitario {0}: {1}. + + failed: + failed: + + failed con errores @@ -1568,12 +1588,12 @@ Defina nombres de perfiles distintos. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + El método '{0}' no se cerró correctamente The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + La directiva debe contener un nombre sin caracteres especiales y un valor opcional separado por "{1}" como "#:{0} Nombre{1}Valor". {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Defina nombres de perfiles distintos. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + La directiva "#:project" no es válida: {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ La herramienta "{1}" (versión "{2}") se instaló correctamente. Se ha agregado A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + Se recibió un nuevo protocolo de enlace "{0}" para la aplicación de prueba que no coincide con el protocolo de enlace anterior "{1}". Missing name of '{0}'. - Missing name of '{0}'. + Falta el nombre de "{0}". {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + Se recibió un evento de inicio de sesión de prueba sin un evento de finalización de sesión de prueba correspondiente. @@ -2502,12 +2522,12 @@ La herramienta "{1}" (versión "{2}") se instaló correctamente. Se ha agregado Invalid property name: {0} - Invalid property name: {0} + Nombre de propiedad no válido {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + La directiva de propiedad debe tener dos partes separadas por "=", como "#:property PropertyName=PropertyValue". {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. El valor predeterminado es publicar una aplicación dependiente del marco. + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Apaga el servidor de compilación de Razor. @@ -2672,6 +2697,11 @@ El valor predeterminado es publicar una aplicación dependiente del marco.Se restauró la herramienta "{0}" (versión "{1}"). Comandos disponibles: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). Reenviar a la versión del marco (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). @@ -2951,6 +2981,11 @@ Su proyecto tiene como destino varias plataformas. Especifique la que quiere usa Omite la creación de archivos de símbolos que se pueden usar para generar perfiles para los ensamblados optimizados. + + skipped: + skipped: + + skipped omitido @@ -3048,7 +3083,7 @@ Su proyecto tiene como destino varias plataformas. Especifique la que quiere usa Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + No se admite la restauración de gráficos estáticos para aplicaciones basadas en archivos. Elimine "#:property". {Locked="#:property"} @@ -3086,6 +3121,11 @@ Su proyecto tiene como destino varias plataformas. Especifique la que quiere usa El entorno tiempo de ejecución de destino para el que se almacenan los paquetes. + + succeeded: + succeeded: + + Summary Resumen @@ -3101,11 +3141,6 @@ Su proyecto tiene como destino varias plataformas. Especifique la que quiere usa Especifique un directorio temporal para que este comando descargue y extraiga paquetes NuGet (debe ser seguro). - - .NET Test Driver - Controlador de pruebas de .NET - - + + total: + total: + + try {0} intento {0} @@ -3559,22 +3599,22 @@ y los identificadores de los paquetes correspondientes a las herramientas instal An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + Se recibió un mensaje inesperado relacionado con la ayuda cuando no se usó "--help". A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + Se recibió un mensaje de tipo "{0}" en modo de ayuda, lo cual no se esperaba. A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + Se recibió un mensaje de tipo "{0}" antes de recibir cualquier protocolo de enlace, lo cual es inesperado. A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + Se recibió un evento de finalización de sesión de prueba sin un evento de inicio de sesión de prueba correspondiente. @@ -3594,7 +3634,7 @@ y los identificadores de los paquetes correspondientes a las herramientas instal Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + Directiva no reconocida "{0}". {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index 13384daa3e4..3b1487a7704 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -186,7 +186,7 @@ Les chemins d’accès ont recherché : « {1} », « {2} ». Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + Vous ne pouvez pas convertir certaines directives. Exécutez le fichier pour voir toutes les erreurs de compilation. Spécifiez « --force » pour convertir quand même. {Locked="--force"} @@ -585,7 +585,7 @@ Cela équivaut à supprimer project.assets.json. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + Spécifie le nombre minimal de tests censés s’exécuter. @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + global.json définit le test runner en tant que Microsoft.Testing.Platform. Tous les projets doivent utiliser ce test runner. +Les projets de test suivants utilisent le test runner VSTest : {0} -See https://aka.ms/dotnet-test/mtp for more information. +Pour découvrir plus d’informations, consultez https://aka.ms/dotnet-test/mtp. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + erreur Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. Découverte des tests à partir de - - .NET Test Command - Commande de test .NET - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Les versions de protocole prises en charge envoyées par Microsoft.Testing.Platform sont « {0} ». Le Kit de développement logiciel (SDK) prend en charge « {1} », ce qui est incompatible. Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + Réception d’un « ExecutionId » de valeur « {0} » pour le message « {1} », alors que « l’ExecutionId » reçu dans le message d’établissement d’une liaison était « {2} ». {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + Erreur lors de la suppression de « NamedPipeServer » correspondant à l’établissement d’une liaison : Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + Erreur lors de la suppression de « NamedPipeServer » et aucun établissement d’une liaison n’a été trouvé. 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + « dotnet » a reçu de manière inattendue moins de 4 octets du canal nommé « dotnet test ». 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + « dotnet » a reçu de manière inattendue des messages qui se chevauchent du canal nommé « dotnet test ». @@ -1228,14 +1233,24 @@ Faites en sorte que les noms de profil soient distincts. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + Les directives dupliquées ne sont pas prises en charge : {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + L’exception suivante s’est produite lors de l’exécution du module de test avec la commande RunCommand « {0} » et les arguments RunArguments « {1} » : {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Faites en sorte que les noms de profil soient distincts. Échec de la mise à jour du manifeste de publicité {0} : {1}. + + failed: + failed: + + failed échec @@ -1568,12 +1588,12 @@ Faites en sorte que les noms de profil soient distincts. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + La méthode « {0} » ne s’est pas arrêtée correctement The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + La directive dans doit contenir un nom sans caractères spéciaux et une valeur facultative séparée par « {1} » comme « # :{0} Nom{1}Valeur ». {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Faites en sorte que les noms de profil soient distincts. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + La directive « #:project » n’est pas valide : {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ L'outil '{1}' (version '{2}') a été correctement installé. L'entrée est ajou A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + Une nouvelle négociation « {0} » a été reçue pour l’application de test, qui ne correspond pas à l’établissement d’une liaison précédente « {1} ». Missing name of '{0}'. - Missing name of '{0}'. + Nom manquant pour « {0} ». {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + Un événement de début de session de test a été reçu sans fin d’une session de test correspondante. @@ -2502,12 +2522,12 @@ L'outil '{1}' (version '{2}') a été correctement installé. L'entrée est ajou Invalid property name: {0} - Invalid property name: {0} + Nom de propriété non valide : {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + La directive de propriété doit avoir deux parties séparées par '=' comme '#:property PropertyName=PropertyValue'. {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. La valeur par défaut est de publier une application dépendante du framework. + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Arrêtez le serveur de builds Razor. @@ -2672,6 +2697,11 @@ La valeur par défaut est de publier une application dépendante du framework.L'outil '{0}' (version '{1}') a été restauré. Commandes disponibles : {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). Restaurer par progression la version du framework (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). @@ -2951,6 +2981,11 @@ Votre projet cible plusieurs frameworks. Spécifiez le framework à exécuter à Ignorez la création de fichiers de symboles pour le profilage des assemblys optimisés. + + skipped: + skipped: + + skipped ignoré @@ -3048,7 +3083,7 @@ Votre projet cible plusieurs frameworks. Spécifiez le framework à exécuter à Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + La restauration de graphique statique n’est pas prise en charge pour les applications basées sur des fichiers. Supprimer la « #:property ». {Locked="#:property"} @@ -3086,6 +3121,11 @@ Votre projet cible plusieurs frameworks. Spécifiez le framework à exécuter à Runtime cible pour lequel le stockage des packages est effectué. + + succeeded: + succeeded: + + Summary Récapitulatif @@ -3101,11 +3141,6 @@ Votre projet cible plusieurs frameworks. Spécifiez le framework à exécuter à Spécifiez un répertoire temporaire pour que cette commande télécharge et extrait les packages NuGet (doit être sécurisé). - - .NET Test Driver - Pilote de test .NET - - + + total: + total: + + try {0} essayer {0} @@ -3559,22 +3599,22 @@ et les ID de package correspondants aux outils installés, utilisez la commande An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + Un message d’aide inattendu a été reçu alors que `--help` n’a pas été utilisé. A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + Un message de type « {0} » a été reçu en mode d’aide, ce qui n’est pas prévu. A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + Un message de type « {0} » a été reçu avant tout établissement d’une liaison, ce qui est inattendu. A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + Un événement de fin de session de test a été reçu sans démarrage d’une session de test correspondante. @@ -3594,7 +3634,7 @@ et les ID de package correspondants aux outils installés, utilisez la commande Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + Directive « {0} » non reconnue. {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index ce5d46f15c1..fffbb67c75e 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -186,7 +186,7 @@ Percorsi cercati: '{1}', '{2}'. Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + Non è possibile convertire alcune direttive. Eseguire il file per visualizzare tutti gli errori di compilazione. Specificare '--force' per eseguire comunque la conversione. {Locked="--force"} @@ -585,7 +585,7 @@ Equivale a eliminare project.assets.json. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + Specifica il numero minimo dei test che si prevede saranno eseguiti. @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + global.json definisce il Test runner come Microsoft.Testing.Platform. Tutti i progetti devono usare tale Test Runner. +I progetti di test seguenti usano il Test Runner VSTest: {0} -See https://aka.ms/dotnet-test/mtp for more information. +Per altre informazioni, vedere https://aka.ms/dotnet-test/mtp. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + errore Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. Individuazione di test da - - .NET Test Command - Comando di test .NET - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Le versioni di protocollo supportate inviate da Microsoft.Testing.Platform sono '{0}'. L'SDK supporta '{1}', che non è compatibile. Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + È stato ricevuto l''ExecutionId' del valore '{0}' per il messaggio '{1}' mentre l''ExecutionId' ricevuto nel messaggio di handshake era '{2}'. {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + Errore durante l'eliminazione del 'NamePipeServer' corrispondente all'handshake: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + Errore durante l'eliminazione di 'NamedPipeServer' e non è stato trovato alcun handshake. 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + 'dotnet' ha ricevuto inaspettatamente meno di 4 byte dal named pipe 'dotnet test'. 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + 'dotnet' ha ricevuto inaspettatamente messaggi sovrapposti dal named pipe 'dotnet test'. @@ -1228,14 +1233,24 @@ Rendi distinti i nomi profilo. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + Le direttive duplicate non supportate: {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + Si è verificata l'eccezione seguente durante l'esecuzione del modulo di test con RunCommand '{0}' e RunArguments '{1}': {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Rendi distinti i nomi profilo. Non è stato possibile scaricare il manifesto di pubblicità {0}: {1}. + + failed: + failed: + + failed operazione non riuscita @@ -1568,12 +1588,12 @@ Rendi distinti i nomi profilo. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + Il metodo '{0}' non è stato chiuso correttamente The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + La direttiva deve contenere un nome senza caratteri speciali e un valore facoltativo delimitato da '{1}' come '#:{0}Nome {1}Valore'. {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Rendi distinti i nomi profilo. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + La direttiva '#:project' non è valida: {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ Lo strumento '{1}' versione '{2}' è stato installato. La voce è stata aggiunta A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + È stato ricevuto un nuovo handshake '{0}' per l'applicazione di test che non corrisponde all'handshake precedente '{1}'. Missing name of '{0}'. - Missing name of '{0}'. + Manca il nome di '{0}'. {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + È stato ricevuto un evento di inizio sessione di test senza un evento di fine sessione corrispondente. @@ -2502,12 +2522,12 @@ Lo strumento '{1}' versione '{2}' è stato installato. La voce è stata aggiunta Invalid property name: {0} - Invalid property name: {0} + Nome proprietà non valido: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + La direttiva di proprietà deve avere due parti delimitate da '=', come '#:property PropertyName=PropertyValue'. {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. Per impostazione predefinita, viene generato un pacchetto dipendente dal framework. + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Arresta il server di compilazione di Razor. @@ -2672,6 +2697,11 @@ Per impostazione predefinita, viene generato un pacchetto dipendente dal framewo Lo strumento '{0}' (versione '{1}') è stato ripristinato. Comandi disponibili: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). Esegue il roll forward alla versione del framework (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). @@ -2951,6 +2981,11 @@ Il progetto è destinato a più framework. Specificare il framework da eseguire Non crea i file di simboli che è possibile usare per la profilatura degli assembly ottimizzati. + + skipped: + skipped: + + skipped ignorato @@ -3048,7 +3083,7 @@ Il progetto è destinato a più framework. Specificare il framework da eseguire Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + Il ripristino statico del grafo non è supportato per le app basate su file. Rimuovere '#:property'. {Locked="#:property"} @@ -3086,6 +3121,11 @@ Il progetto è destinato a più framework. Specificare il framework da eseguire Runtime di destinazione per cui archiviare i pacchetti. + + succeeded: + succeeded: + + Summary Riepilogo @@ -3101,11 +3141,6 @@ Il progetto è destinato a più framework. Specificare il framework da eseguire Specificare una directory temporanea per questo comando per scaricare ed estrarre i pacchetti NuGet (deve essere protetta). - - .NET Test Driver - Driver di test .NET - - + + total: + total: + + try {0} prova {0} @@ -3559,22 +3599,22 @@ e gli ID pacchetto corrispondenti per gli strumenti installati usando il comando An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + È stato ricevuto un messaggio imprevisto relativo alla Guida quando non è stato usato '--help'. A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + È stato ricevuto un messaggio di tipo '{0}' in modalità Guida, cosa non prevista. A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + È stato ricevuto un messaggio di tipo '{0}' prima di ricevere handshake, cosa imprevista. A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + È stato ricevuto un evento di fine sessione di test senza un evento di inizio sessione corrispondente. @@ -3594,7 +3634,7 @@ e gli ID pacchetto corrispondenti per gli strumenti installati usando il comando Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + Direttiva non riconosciuta '{0}'. {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index cd98c4d622a..4a9b4564cd8 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -186,7 +186,7 @@ Paths searched: '{1}', '{2}'. Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + 一部のディレクティブは変換できません。ファイルを実行して、すべてのコンパイル エラーを表示します。それでも変換する場合は '--force' を指定してください。 {Locked="--force"} @@ -585,7 +585,7 @@ This is equivalent to deleting project.assets.json. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + 実行する必要があるテストの最小数を指定します。 @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + global.json では、テスト ランナーを Microsoft.Testing.Platform と定義します。すべてのプロジェクトで、そのテスト ランナーを使用する必要があります。 +次のテスト プロジェクトでは、VSTest テスト ランナーを使用しています: {0} -See https://aka.ms/dotnet-test/mtp for more information. +詳細については、https://aka.ms/dotnet-test/mtp を参照してください。 {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + エラー Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. からテストを検出しています - - .NET Test Command - .NET Test コマンド - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Microsoft.Testing.Platform から送信されたサポートされているプロトコル バージョンは '{0}' です。SDK は互換性のない '{1}' をサポートしています。 Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + ハンドシェイク メッセージで受信した 'ExecutionId' が '{0}' のときに、メッセージ '{1}' の 'ExecutionId' 値 '{2}' を受信しました。 {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + ハンドシェイクに対応する 'NamedPipeServer' の破棄中にエラーが発生しました: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + 'NamedPipeServer' の破棄中にエラーが発生し、ハンドシェイクが見つかりませんでした。 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + 'dotnet' は 'dotnet test' 名前付きパイプから予期せず 4 バイト未満を受信しました。 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + 'dotnet' は 'dotnet test' 名前付きパイプから予期せず重複するメッセージを受信しました。 @@ -1228,14 +1233,24 @@ Make the profile names distinct. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + 重複するディレクティブはサポートされていません: {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + RunCommand '{0}' および RunArguments '{1}' でテスト モジュールを実行中に、次の例外が発生しました: {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Make the profile names distinct. 広告マニフェスト {0} を更新できませんでした: {1}。 + + failed: + failed: + + failed 失敗 @@ -1568,12 +1588,12 @@ Make the profile names distinct. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + メソッド '{0}' が正常に終了しませんでした The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + ディレクティブには、特殊文字を含まない名前と、'#:{0} Name{1}Value' などの '{1}' で区切られた省略可能な値を含める必要があります。 {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Make the profile names distinct. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + '#:p roject' ディレクティブが無効です: {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + テスト アプリケーションに対して、前回のハンドシェイク '{0}' と一致しない新しいハンドシェイク '{1}' を受信しました。 Missing name of '{0}'. - Missing name of '{0}'. + '{0}' の名前がありません。 {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + 対応するテスト セッションの終了がないまま、テスト セッション開始イベントを受信しました。 @@ -2502,12 +2522,12 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man Invalid property name: {0} - Invalid property name: {0} + 無効なプロパティ名: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + プロパティ ディレクティブには、'#:property PropertyName=PropertyValue' のように '=' で区切られた 2 つの部分が必要です。 {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. 既定では、フレームワークに依存したアプリケーションが公開されます。 + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Razor ビルド サーバーをシャットダウンします。 @@ -2672,6 +2697,11 @@ The default is to publish a framework-dependent application. ツール '{0}' (バージョン '{1}') は復元されました。使用できるコマンド: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). フレームワーク バージョン (LatestPatch、Minor、LatestMinor、Major、LatestMajor、Disable) にロールフォワードします。 @@ -2951,6 +2981,11 @@ Your project targets multiple frameworks. Specify which framework to run using ' 最適化されたアセンブリのプロファイルに使用できるシンボル ファイルの作成をスキップします。 + + skipped: + skipped: + + skipped スキップされました @@ -3048,7 +3083,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + 静的グラフの復元はファイルベースのアプリではサポートされていません。'#:property' を削除します。 {Locked="#:property"} @@ -3086,6 +3121,11 @@ Your project targets multiple frameworks. Specify which framework to run using ' パッケージを格納するターゲット ランタイム。 + + succeeded: + succeeded: + + Summary 概要 @@ -3101,11 +3141,6 @@ Your project targets multiple frameworks. Specify which framework to run using ' このコマンドに NuGet パッケージをダウンロードして抽出するための一時ディレクトリを指定します (セキュリティで保護する必要があります)。 - - .NET Test Driver - .NET Test Driver - - + + total: + total: + + try {0} {0} を試す @@ -3559,22 +3599,22 @@ and the corresponding package Ids for installed tools using the command An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + '--help' が使用されていないときに、予期しないヘルプ関連のメッセージを受信しました。 A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + 種類 '{0}' のメッセージをヘルプ モードで受信しましたが、これは想定されていません。 A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + ハンドシェイクを受信する前に、種類 '{0}' のメッセージを受信しましたが、これは想定されていません。 A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + 対応するテスト セッションの開始がないまま、テスト セッション終了イベントを受信しました。 @@ -3594,7 +3634,7 @@ and the corresponding package Ids for installed tools using the command Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + 認識されないディレクティブ '{0}' です。 {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index f1840d63dcf..d7a462877fb 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -186,7 +186,7 @@ Paths searched: '{1}', '{2}'. Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + 일부 지시문을 변환할 수 없습니다. 파일을 실행하여 모든 컴파일 오류를 확인하세요. 변환을 강제로 진행하려면 '--force'를 지정하세요. {Locked="--force"} @@ -585,7 +585,7 @@ project.assets.json을 삭제하는 것과 동일합니다. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + 실행될 것으로 예상되는 최소 테스트 수를 지정합니다. @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + global.json은 Test Runner를 Microsoft.Testing.Platform으로 정의합니다. 모든 프로젝트는 해당 Test Runner를 사용해야 합니다. +다음 테스트 프로젝트에서 VSTest Test Runner를 사용하고 있습니다. {0} -See https://aka.ms/dotnet-test/mtp for more information. +자세한 내용은 https://aka.ms/dotnet-test/mtp를 참조하세요. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + 오류 Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. 다음에서 테스트 검색하는 중 - - .NET Test Command - .NET 테스트 명령 - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Microsoft.Testing.Platform에서 보낸 지원되는 프로토콜 버전은 '{0}'입니다. SDK는 호환되지 않는 '{1}'을(를) 지원합니다. Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + 핸드셰이크 메시지에서 받은 'ExecutionId'가 '{2}'인 동안 메시지 '{1}'에 대해 값 '{0}'의 'ExecutionId'가 수신되었습니다. {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + 핸드셰이크에 해당하는 'NamedPipeServer'를 삭제하는 동안 오류가 발생했습니다. Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + 'NamedPipeServer'를 삭제하는 동안 오류가 발생하여 핸드셰이크를 찾을 수 없습니다. 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + 'dotnet'이 'dotnet test'로 명명된 파이프에서 예기치 않게 4바이트 미만의 데이터를 받았습니다. 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + 'dotnet'이 'dotnet test'로 명명된 파이프에서 예기치 않게 겹치는 메시지를 받았습니다. @@ -1228,14 +1233,24 @@ Make the profile names distinct. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + 중복 지시문은 지원되지 않습니다. {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + RunCommand '{0}' 및 RunArguments '{1}'(으)로 테스트 모듈을 실행하는 동안 다음 예외가 발생했습니다. {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Make the profile names distinct. 광고 매니페스트 {0}: {1}을(를) 업데이트하지 못했습니다. + + failed: + failed: + + failed 실패 @@ -1568,12 +1588,12 @@ Make the profile names distinct. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + '{0}' 메서드가 성공적으로 종료되지 않았습니다. The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + 지시문에는 특수 문자가 없는 이름과 '#:{0} 이름{1}값'과 같이 '{1}'(으)로 구분된 선택적 값이 포함되어야 합니다. {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Make the profile names distinct. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + '#:p roject' 지시문이 잘못되었습니다. {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + 이전 핸드셰이크 '{1}'과(와) 일치하지 않는 테스트 애플리케이션에 대해 새 핸드셰이크 '{0}'이(가) 수신되었습니다. Missing name of '{0}'. - Missing name of '{0}'. + '{0}' 이름이 없습니다. {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + 해당 테스트 세션 종료 없이 테스트 세션 시작 이벤트를 받았습니다. @@ -2502,12 +2522,12 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man Invalid property name: {0} - Invalid property name: {0} + 잘못된 속성 이름: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + property 지시문에는 '#:property PropertyName=PropertyValue'와 같이 '='로 구분된 두 부분이 있어야 합니다. {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. 기본값은 프레임워크 종속 애플리케이션을 게시하는 것입니다. + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Razor 빌드 서버를 종료합니다. @@ -2672,6 +2697,11 @@ The default is to publish a framework-dependent application. '{0}' 도구(버전 '{1}')가 복원되었습니다. 사용 가능한 명령: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). 프레임워크 버전(LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable)으로 롤포워드합니다. @@ -2951,6 +2981,11 @@ Your project targets multiple frameworks. Specify which framework to run using ' 최적화된 어셈블리 프로파일링에 대해 사용할 수 있는 기호 파일 만들기를 건너뜁니다. + + skipped: + skipped: + + skipped 건너뜀 @@ -3048,7 +3083,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + 정적 그래프 복원은 파일 기반 앱에서 지원되지 않습니다. '#:property'를 제거합니다. {Locked="#:property"} @@ -3086,6 +3121,11 @@ Your project targets multiple frameworks. Specify which framework to run using ' 패키지를 저장할 대상 런타임입니다. + + succeeded: + succeeded: + + Summary 요약 @@ -3101,11 +3141,6 @@ Your project targets multiple frameworks. Specify which framework to run using ' NuGet 패키지를 다운로드하고 추출하려면 이 명령의 임시 디렉터리를 지정합니다(보안이 있어야 합니다). - - .NET Test Driver - .NET 테스트 드라이버 - - + + total: + total: + + try {0} {0} 시도 @@ -3559,22 +3599,22 @@ and the corresponding package Ids for installed tools using the command An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + '--help'를 사용하지 않았는데 예기치 않은 도움말 관련 메시지를 받았습니다. A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + 도움말 모드에서 예상치 못하게 '{0}' 형식의 메시지를 받았습니다. A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + 핸드셰이크를 받기 전에 예기치 않게 '{0}' 형식의 메시지가 수신되었습니다. A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + 해당 테스트 세션을 시작하지 않고 테스트 세션 종료 이벤트를 받았습니다. @@ -3594,7 +3634,7 @@ and the corresponding package Ids for installed tools using the command Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + 인식할 수 없는 지시문 '{0}'입니다. {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index 18f7a5dd14c..455c06c0f7d 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -186,7 +186,7 @@ Przeszukane ścieżki: „{1}”, „{2}”. Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + Nie można przekonwertować niektórych dyrektyw. Uruchom plik, aby wyświetlić wszystkie błędy kompilacji. Określ element „--force”, aby mimo to przekonwertować. {Locked="--force"} @@ -585,7 +585,7 @@ Jest to równoważne usunięciu pliku project.assets.json. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + Określa minimalną liczbę testów, które mają zostać uruchomione. @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + global.json definiuje moduł uruchamiający testy jako Microsoft.Testing.Platform. Wszystkie projekty muszą używać tego modułu uruchamiającego testy. +Następujące projekty testowe używają modułu uruchamiającego testy VSTest: {0} -See https://aka.ms/dotnet-test/mtp for more information. +Aby uzyskać więcej informacji, zobacz https://aka.ms/dotnet-test/mtp. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + błąd Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. Odnajdywanie testów w - - .NET Test Command - Polecenie testowe platformy .NET - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Obsługiwane wersje protokołów wysyłane przez element Microsoft.Testing.Platform to „{0}”. Zestaw SDK obsługuje element „{1}”, co jest niezgodne. Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + Odebrano wartość „ExecutionId” dla{0}komunikatu „{1}”, a element „ExecutionId” odebrany z komunikatu uzgadniania to „{2}”. {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + Błąd usuwania elementu „NamedPipeServer” odpowiadającego uzgadnianiu: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + Wystąpił błąd podczas usuwania elementu „NamedPipeServer” i nie znaleziono uzgadniania. 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + Element „dotnet” nieoczekiwanie odebrał mniej niż 4 bajty z nazwanego potoku "dotnet test". 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + Element "dotnet" nieoczekiwanie odebrał nakładające się komunikaty z nazwanego potoku „dotnet test”. @@ -1228,14 +1233,24 @@ Rozróżnij nazwy profilów. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + Zduplikowane dyrektywy nie są obsługiwane: {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + Wystąpił następujący wyjątek podczas uruchamiania modułu testowego z elementami RunCommand „{0}” i RunArguments „{1}”: {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Rozróżnij nazwy profilów. Nie można zaktualizować manifestu anonsowania {0}: {1}. + + failed: + failed: + + failed zakończone niepowodzeniem @@ -1568,12 +1588,12 @@ Rozróżnij nazwy profilów. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + Metoda „{0}” nie zakończyła się pomyślnie The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + Dyrektywa powinna zawierać nazwę bez znaków specjalnych i opcjonalną wartość rozdzieloną znakiem "{1}#:{0} Name{1}Value". {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Rozróżnij nazwy profilów. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + Dyrektywa „#:project” jest nieprawidłowa: {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ Narzędzie „{1}” (wersja „{2}”) zostało pomyślnie zainstalowane. Wpis A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + Odebrano nowe uzgadnianie „{0}” dla aplikacji testowej, która nie pasuje do poprzedniego uzgadniania „{1}”. Missing name of '{0}'. - Missing name of '{0}'. + Brak nazwy „{0}”. {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + Odebrano zdarzenie rozpoczęcia sesji testowej bez odpowiedniego zakończenia sesji testowej. @@ -2502,12 +2522,12 @@ Narzędzie „{1}” (wersja „{2}”) zostało pomyślnie zainstalowane. Wpis Invalid property name: {0} - Invalid property name: {0} + Nieprawidłowa nazwa właściwości: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + Dyrektywa właściwości musi mieć dwie części oddzielone znakiem „=”, na przykład „#:property PropertyName=PropertyValue”. {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. Domyślnie publikowana jest aplikacja zależna od struktury. + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Zamknij serwer kompilacji Razor. @@ -2672,6 +2697,11 @@ Domyślnie publikowana jest aplikacja zależna od struktury. Narzędzie „{0}” (wersja „{1}”) zostało przywrócone. Dostępne polecenia: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). Przewiń do wersji platformy (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). @@ -2951,6 +2981,11 @@ Projekt ma wiele platform docelowych. Określ platformę do uruchomienia przy u Pomiń tworzenie plików symboli, za pomocą których można profilować zoptymalizowane zestawy. + + skipped: + skipped: + + skipped pominięte @@ -3048,7 +3083,7 @@ Projekt ma wiele platform docelowych. Określ platformę do uruchomienia przy u Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + Przywracanie statycznego grafu nie jest obsługiwane w przypadku aplikacji opartych na plikach. Usuń element „#:property”. {Locked="#:property"} @@ -3086,6 +3121,11 @@ Projekt ma wiele platform docelowych. Określ platformę do uruchomienia przy u Docelowe środowisko uruchomieniowe, dla którego mają być przechowywane pakiety. + + succeeded: + succeeded: + + Summary Podsumowanie @@ -3101,11 +3141,6 @@ Projekt ma wiele platform docelowych. Określ platformę do uruchomienia przy u Określ katalog tymczasowy dla tego polecenia, aby pobrać i wyodrębnić pakiety NuGet (musi być bezpieczny). - - .NET Test Driver - Sterownik testów platformy .NET - - + + total: + total: + + try {0} wypróbuj {0} @@ -3559,22 +3599,22 @@ i odpowiednie identyfikatory pakietów zainstalowanych narzędzi można znaleź An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + Odebrano nieoczekiwany komunikat związany z pomocą, gdy nie użyto elementu „--help”. A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + Komunikat typu „{0}” został odebrany w trybie pomocy, co nie jest oczekiwane. A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + Komunikat typu „{0}” został odebrany przed otrzymaniem jakichkolwiek uzgadniań, co jest nieoczekiwane. A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + Odebrano zdarzenie zakończenia sesji testowej bez odpowiedniego uruchomienia sesji testowej. @@ -3594,7 +3634,7 @@ i odpowiednie identyfikatory pakietów zainstalowanych narzędzi można znaleź Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + Nierozpoznana dyrektywa „{0}”. {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index 0ae92622b31..f999a934e37 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -186,7 +186,7 @@ Caminhos pesquisados: "{1}", "{2}". Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + Algumas diretivas não podem ser convertidas. Execute o arquivo para ver todos os erros de compilação. Especifique '--force' para converter mesmo assim. {Locked="--force"} @@ -585,7 +585,7 @@ Isso equivale a excluir o project.assets.json. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + Especifica o número mínimo de testes que devem ser executados. @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + O global.json define o executor de teste como Microsoft.Testing.Platform. Todos os projetos devem usar esse executor de teste. +Os seguintes projetos de teste estão usando o executor de teste do VSTest: {0} -See https://aka.ms/dotnet-test/mtp for more information. +Consulte https://aka.ms/dotnet-test/mtp para obter mais informações. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + erro Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. Descobrindo testes de - - .NET Test Command - Comando de Teste do .NET - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + As versões de protocolo suportadas enviadas pelo Microsoft.Testing.Platform são '{0}'. O SDK oferece suporte a '{1}', que é incompatível. Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + Recebido 'ExecutionId' com valor '{0}' para a mensagem '{1}', enquanto o 'ExecutionId' recebido na mensagem de handshake era '{2}'. {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + Erro ao descartar 'NamedPipeServer' correspondente ao handshake: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + Erro ao descartar 'NamedPipeServer', e nenhum handshake foi encontrado. 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + O 'dotnet' recebeu inesperadamente menos de 4 bytes do pipe nomeado 'dotnet test'. 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + O 'dotnet' recebeu inesperadamente mensagens sobrepostas do pipe nomeado 'dotnet test'. @@ -1228,14 +1233,24 @@ Diferencie os nomes dos perfis. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + Diretivas duplicadas não são suportadas:{0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + A seguinte exceção ocorreu ao executar o módulo de teste com RunCommand '{0}' e RunArguments '{1}': {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Diferencie os nomes dos perfis. Falha ao atualizar o manifesto de publicidade {0}: {1}. + + failed: + failed: + + failed com falha @@ -1568,12 +1588,12 @@ Diferencie os nomes dos perfis. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + O método '{0}' não foi concluído com sucesso The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + A diretiva deve conter um nome sem caracteres especiais e um valor opcional separado por '{1}' como '#:{0} Nome{1}Valor'. {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Diferencie os nomes dos perfis. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + A diretiva '#:project' é inválida:{0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ A ferramenta '{1}' (versão '{2}') foi instalada com êxito. A entrada foi adici A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + Um novo handshake '{0}' foi recebido para o aplicativo de teste que não corresponde ao handshake anterior '{1}'. Missing name of '{0}'. - Missing name of '{0}'. + Nome de '{0}' ausente. {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + Um evento de início de sessão de teste foi recebido sem um término de sessão de teste correspondente. @@ -2502,12 +2522,12 @@ A ferramenta '{1}' (versão '{2}') foi instalada com êxito. A entrada foi adici Invalid property name: {0} - Invalid property name: {0} + Nome de propriedade inválido: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + A diretiva de propriedade precisa ter duas partes separadas por '=' como '#:property PropertyName=PropertyValue'. {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. O padrão é publicar uma aplicação dependente de framework. + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Desligar o servidor de build do Razor. @@ -2672,6 +2697,11 @@ O padrão é publicar uma aplicação dependente de framework. A ferramenta '{0}' (versão '{1}') foi restaurada. Comandos disponíveis: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). Role para frente para a versão de estrutura (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). @@ -2951,6 +2981,11 @@ Ele tem diversas estruturas como destino. Especifique que estrutura executar usa Ignorar a criação de arquivos de símbolo que podem ser usados para criar o perfil de assemblies otimizados. + + skipped: + skipped: + + skipped ignorado @@ -3048,7 +3083,7 @@ Ele tem diversas estruturas como destino. Especifique que estrutura executar usa Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + A restauração de grafo estático não é suportada para aplicativos baseados em arquivos. Remova '#:property'. {Locked="#:property"} @@ -3086,6 +3121,11 @@ Ele tem diversas estruturas como destino. Especifique que estrutura executar usa O runtime de destino no qual os pacotes serão armazenados. + + succeeded: + succeeded: + + Summary Resumo @@ -3101,11 +3141,6 @@ Ele tem diversas estruturas como destino. Especifique que estrutura executar usa Especifique um diretório temporário para este comando baixar e extrair pacotes NuGet (deve ser seguro). - - .NET Test Driver - Driver de Teste do .NET - - + + total: + total: + + try {0} experimente {0} @@ -3559,22 +3599,22 @@ e as Ids de pacote correspondentes para as ferramentas instaladas usando o coman An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + Uma mensagem inesperada relacionada à ajuda foi recebida quando `--help` não foi usado. A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + Uma mensagem do tipo '{0}' foi recebida no modo de ajuda, o que não era esperado. A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + Uma mensagem do tipo '{0}' foi recebida antes de qualquer handshake, o que é inesperado. A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + Um evento de término de sessão de teste foi recebido sem um início de sessão de teste correspondente. @@ -3594,7 +3634,7 @@ e as Ids de pacote correspondentes para as ferramentas instaladas usando o coman Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + Diretiva não reconhecida '{0}'. {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index c8d7414bf34..adae2e4b3b1 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -186,7 +186,7 @@ Paths searched: '{1}', '{2}'. Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + Некоторые директивы невозможно преобразовать. Запустите файл, чтобы увидеть все ошибки компиляции. Укажите параметр "--force", чтобы выполнить преобразование, невзирая на ошибки. {Locked="--force"} @@ -585,7 +585,7 @@ This is equivalent to deleting project.assets.json. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + Указывает минимальное число тестов, которые должны быть запущены. @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + В global.json в качестве средства выполнения тестов указано Microsoft.Testing.Platform. Все проекты должны использовать это средство выполнения тестов. +Следующие тестовые проекты используют средство выполнения тестов VSTest: {0} -See https://aka.ms/dotnet-test/mtp for more information. +Дополнительные сведения см. на странице https://aka.ms/dotnet-test/mtp. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + ошибка Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. Обнаружение тестов из - - .NET Test Command - Команда .NET Test - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Поддерживаемые версии протокола, отправленные при помощи Microsoft.Testing.Platform: "{0}". SDK поддерживает "{1}", что несовместимо. Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + Получено "ExecutionId" со значением "{0}" для сообщения "{1}", тогда как "ExecutionId" в сообщении подтверждения был "{2}". {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + Ошибка при удалении "NamedPipeServer", соответствующего подтверждению: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + Ошибка при удалении "NamedPipeServer", подтверждение не найдено. 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + "dotnet" неожиданно получил менее 4 байт из именованного канала "dotnet test". 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + "dotnet" неожиданно получил перекрывающиеся сообщения из именованного канала "dotnet test". @@ -1228,14 +1233,24 @@ Make the profile names distinct. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + Повторяющиеся директивы не поддерживаются: {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + При выполнении тестового модуля с RunCommand "{0}" и RunArguments "{1}" возникло следующее исключение: {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Make the profile names distinct. Не удалось обновить манифест рекламы {0}: {1}. + + failed: + failed: + + failed сбой @@ -1568,12 +1588,12 @@ Make the profile names distinct. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + Сбой выхода метода "{0}" The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + Директива должна содержать имя без специальных символов и необязательное значение, разделенные символом-разделителем "{1}", например "#:{0} Имя{1}Значение". {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Make the profile names distinct. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + Недопустимая директива "#:project": {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + Получено новое подтверждение "{0}" для тестового приложения, которое не совпадает с предыдущим подтверждением "{1}". Missing name of '{0}'. - Missing name of '{0}'. + Отсутствует имя "{0}". {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + Получено событие запуска тестового сеанса без соответствующего завершения тестового сеанса. @@ -2502,12 +2522,12 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man Invalid property name: {0} - Invalid property name: {0} + Недопустимое имя свойства: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + Директива свойства должна иметь две части, разделенные символом "=", например "#:property PropertyName=PropertyValue". {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. По умолчанию публикация выполняется в приложение, зависимое от платформы. + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Завершает работу сервера сборки Razor. @@ -2672,6 +2697,11 @@ The default is to publish a framework-dependent application. Средство "{0}" (версия "{1}") было восстановлено. Доступные команды: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). Накат до версии платформы (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). @@ -2951,6 +2981,11 @@ Your project targets multiple frameworks. Specify which framework to run using ' Пропуск создания файлов символов, которые можно использовать для профилирования оптимизированных сборок. + + skipped: + skipped: + + skipped пропущено @@ -3048,7 +3083,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + Восстановление статического графа не поддерживается для приложений на основе файлов. Удалите "#:property". {Locked="#:property"} @@ -3086,6 +3121,11 @@ Your project targets multiple frameworks. Specify which framework to run using ' Целевая среда выполнения, для которой хранятся пакеты. + + succeeded: + succeeded: + + Summary Сводка @@ -3101,11 +3141,6 @@ Your project targets multiple frameworks. Specify which framework to run using ' Укажите временный каталог для этой команды, чтобы скачать и извлечь пакеты NuGet (должны быть защищены). - - .NET Test Driver - Драйвер тестов .NET - - + + total: + total: + + try {0} попробуйте {0} @@ -3560,22 +3600,22 @@ and the corresponding package Ids for installed tools using the command An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + Получено неожиданное сообщение, связанное со справкой, без использования параметра "--help". A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + В режиме справки получено сообщение типа "{0}", что является неожиданным. A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + Сообщение типа "{0}" получено до получения каких-либо подтверждений, что является неожиданным. A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + Получено событие завершения тестового сеанса без соответствующего запуска тестового сеанса. @@ -3595,7 +3635,7 @@ and the corresponding package Ids for installed tools using the command Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + Нераспознанная директива "{0}". {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index 662a06fd8fb..4e19bf47de4 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -186,7 +186,7 @@ Aranan yollar: '{1}', '{2}'. Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + Bazı yönergeler dönüştürülemez. Tüm derleme hatalarını görmek için dosyayı çalıştırın. Yine de dönüştürmek için '--force' belirtin. {Locked="--force"} @@ -585,7 +585,7 @@ project.assets.json öğesini silmeyle eşdeğerdir. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + Çalıştırılması beklenen en düşük test sayısını belirtir. @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + global.json, test çalıştırıcısını Microsoft.Testing.Platform olarak tanımlar. Tüm projelerin bu test çalıştırıcısını kullanması gereklidir. +Aşağıdaki test projeleri VSTest test çalıştırıcısını kullanıyor: {0} -See https://aka.ms/dotnet-test/mtp for more information. +Daha fazla bilgi için https://aka.ms/dotnet-test/mtp adresine bakın. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + hata Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. Testler şuradan bulunuyor: - - .NET Test Command - .NET Test Komutu - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Microsoft.Testing.Platform tarafından gönderilen desteklenen protokol sürümleri: '{0}'. SDK, uyumsuz olan '{1}' öğesini desteklemektedir. Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + El sıkışma mesajının aldığı ‘ExecutionId’ değeri '{2}' iken, '{1}' mesajı için '{0}' değerinde ‘ExecutionId’ alındı. {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + El sıkışma ile ilgili 'NamedPipeServer'ın atımında hata oluştu: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + 'NamedPipeServer'ın atımında hata oluştu ve el sıkışma bulunamadı. 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + ‘dotnet’, ‘dotnet test’ adlandırılmış kanaldan beklenmedik bir şekilde 4 bayttan az veri aldı. 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + ‘dotnet’, ‘dotnet test’ adlandırılmış kanaldan beklenmedik bir şekilde çakışan mesajlar aldı. @@ -1228,14 +1233,24 @@ Lütfen profil adlarını değiştirin. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + Yinelenen yönergeler desteklenmez: {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + RunCommand '{0}' ve RunArguments '{1}' ile test modülünü çalıştırırken aşağıdaki istisna oluştu: {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Lütfen profil adlarını değiştirin. Reklam bildirimi {0} güncelleştirilemedi: {1}. + + failed: + failed: + + failed başarısız @@ -1568,12 +1588,12 @@ Lütfen profil adlarını değiştirin. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + '{0}' yöntemi başarıyla çıkmadı The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + Yönerge, özel karakterler içermeyen bir ad ve ‘#:{0} Ad{1}Değer’ gibi '{1}' ile ayrılmış isteğe bağlı bir değer içermelidir. {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Lütfen profil adlarını değiştirin. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + ‘#:project’ yönergesi geçersizdir: {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + Test uygulaması için önceki el sıkışma '{1}' ile eşleşmeyen yeni bir el sıkışma '{0}' alındı. Missing name of '{0}'. - Missing name of '{0}'. + '{0}' adı eksik. {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + Karşılık gelen test oturumu sonu olmadan bir test oturumu başlangıç olayı alındı. @@ -2502,12 +2522,12 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man Invalid property name: {0} - Invalid property name: {0} + Geçersiz özellik adı: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + Özellik yönergesi, ‘#:property PropertyName=PropertyValue’ gibi ‘=’ ile ayrılmış iki bölümden oluşmalıdır. {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. Varsayılan durum, çerçeveye bağımlı bir uygulama yayımlamaktır. + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. Razor derleme sunucusunu kapatır. @@ -2672,6 +2697,11 @@ Varsayılan durum, çerçeveye bağımlı bir uygulama yayımlamaktır. '{0}' aracı (sürüm '{1}') geri yüklendi. Kullanılabilen komutlar: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). Şu framework sürümüne ileri sarın: (LatestPatch, İkincil, LatestMinor, Ana, LatestMajor, Devre dışı). @@ -2951,6 +2981,11 @@ Projeniz birden fazla Framework'ü hedefliyor. '{0}' kullanarak hangi Framework' İyileştirilen bütünleştirilmiş kodların profilini oluşturmak için kullanılabilen sembol dosyalarını oluşturma işlemini atlar. + + skipped: + skipped: + + skipped atlandı @@ -3048,7 +3083,7 @@ Projeniz birden fazla Framework'ü hedefliyor. '{0}' kullanarak hangi Framework' Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + Dosya tabanlı uygulamalar için statik grafik geri yükleme desteklenmemektedir. ‘#:property’i kaldırın. {Locked="#:property"} @@ -3086,6 +3121,11 @@ Projeniz birden fazla Framework'ü hedefliyor. '{0}' kullanarak hangi Framework' Paketlerin geri yükleneceği hedef çalışma zamanı. + + succeeded: + succeeded: + + Summary Özet @@ -3101,11 +3141,6 @@ Projeniz birden fazla Framework'ü hedefliyor. '{0}' kullanarak hangi Framework' Bu komut için NuGet paketlerini indirmek ve ayıklamak üzere geçici bir dizin belirtin (güvenli olmalıdır). - - .NET Test Driver - .NET Test Sürücüsü - - + + total: + total: + + try {0} Şunu deneyin: {0} @@ -3559,22 +3599,22 @@ karşılık gelen paket kimliklerini bulmak için An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + `--help` kullanılmadığında beklenmedik bir yardım mesajı alındı. A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + Yardım modunda '{0}' türünde bir mesaj alındı, bu beklenmeyen bir durumdur. A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + Herhangi bir el sıkışma almadan önce '{0}' türünde bir mesaj alındı, bu beklenmedik bir durumdur. A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + Karşılık gelen test oturumu başlangıcı olmadan bir test oturumu bitiş olayı alındı. @@ -3594,7 +3634,7 @@ karşılık gelen paket kimliklerini bulmak için Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + Tanınmayan yönerge '{0}'. {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index d292dec919f..85e43f3d508 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -186,7 +186,7 @@ Paths searched: '{1}', '{2}'. Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + 一些指令无法转换。运行该文件以查看所有编译错误。请指定 '--force' 以进行转换。 {Locked="--force"} @@ -585,7 +585,7 @@ This is equivalent to deleting project.assets.json. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + 指定预期运行的最小测试数。 @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + global.json 定义将测试运行器定义为 Microsoft.Testing.Platform。所有项目都必须使用该测试运行器。 +以下测试项目正在使用 VSTest 测试运行器: {0} -See https://aka.ms/dotnet-test/mtp for more information. +有关详细信息,请参阅 https://aka.ms/dotnet-test/mtp。 {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + 错误 Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. 正在发现以下位置中的测试 - - .NET Test Command - .NET 测试命令 - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Microsoft.Testing.Platform 发送的受支持的协议版本为 ‘{0}’。SDK 支持 ‘{1}’,这是不兼容的。 Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + 收到了消息 ‘{1}’ 的值为 ‘{0}’ 的 ‘ExecutionId’,而 ‘ExecutionId’ 收到的握手消息为 ‘{2}’。 {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + 释放与握手对应的 'NamedPipeServer' 时出错: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + 释放 'NamedPipeServer' 时出错,未找到握手。 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + 'dotnet' 意外从 'dotnet test' 命名管道接收了不到 4 个字节。 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + 'dotnet' 意外从 'dotnet test' 命名管道接收了重叠的消息。 @@ -1228,14 +1233,24 @@ Make the profile names distinct. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + 不支持重复指令: {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + 使用 RunCommand ‘{0}’ 和 RunArguments ‘{1}’ 运行测试模块时发生以下异常: {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Make the profile names distinct. 未能更新广告清单 {0}: {1}。 + + failed: + failed: + + failed 失败 @@ -1568,12 +1588,12 @@ Make the profile names distinct. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + 方法“{0}”未成功退出 The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + 该指令应包含一个不带特殊字符的名称,以及一个以 '#:{0} Name{1}Value' 等 ‘{1}’ 分隔的可选值。 {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Make the profile names distinct. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + '#:project' 指令无效: {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + 测试应用程序收到了新的握手 ‘{0}’,它与以前的握手 ‘{1}’ 不匹配。 Missing name of '{0}'. - Missing name of '{0}'. + 缺少 '{0}' 的名称。 {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + 在没有相应的测试会话结束的情况下收到了测试会话开始事件。 @@ -2502,12 +2522,12 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man Invalid property name: {0} - Invalid property name: {0} + 属性名无效: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + 属性指令需要包含两个由 ‘=’ 分隔的部件,例如 '#:property PropertyName=PropertyValue'。 {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. 默认情况下发布依赖于框架的应用程序。 + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. 关闭 Razor 生成服务器。 @@ -2672,6 +2697,11 @@ The default is to publish a framework-dependent application. 工具“{0}”(版本“{1}”)已还原。可用的命令: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). 前滚至框架版本(LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable)。 @@ -2951,6 +2981,11 @@ Your project targets multiple frameworks. Specify which framework to run using ' 跳过符号文件的创建操作,这些文件可用于分析已优化的程序集。 + + skipped: + skipped: + + skipped 已跳过 @@ -3048,7 +3083,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + 基于文件的应用不支持静态图形还原。移除 '#:property'。 {Locked="#:property"} @@ -3086,6 +3121,11 @@ Your project targets multiple frameworks. Specify which framework to run using ' 要存储包的目标运行时。 + + succeeded: + succeeded: + + Summary 摘要 @@ -3101,11 +3141,6 @@ Your project targets multiple frameworks. Specify which framework to run using ' 为此命令指定一个临时目录,以下载并提取(必须安全)的 NuGet 包。 - - .NET Test Driver - .NET 测试驱动程序 - - + + total: + total: + + try {0} 尝试 {0} @@ -3559,22 +3599,22 @@ and the corresponding package Ids for installed tools using the command An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + 未使用 `--help` 时收到了与帮助相关的意外消息。 A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + 在帮助模式下收到类型为 ‘{0}’ 的消息,这是预期的事件。 A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + 在我们收到任何握手之前已收到类型为 ‘{0}’ 的消息,这是意外的行为。 A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + 在没有相应的测试会话启动的情况下收到了测试会话结束事件。 @@ -3594,7 +3634,7 @@ and the corresponding package Ids for installed tools using the command Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + 无法识别的指令 ‘{0}’。 {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index 77d4e805d58..7023d8771c0 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -186,7 +186,7 @@ Paths searched: '{1}', '{2}'. Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. - Some directives cannot be converted. Run the file to see all compilation errors. Specify '--force' to convert anyway. + 無法轉換某些指示詞。執行檔案以查看所有編譯錯誤。指定 '--force' 以繼續轉換。 {Locked="--force"} @@ -585,7 +585,7 @@ This is equivalent to deleting project.assets.json. Specifies the minimum number of tests that are expected to run. - Specifies the minimum number of tests that are expected to run. + 指定預期執行的測試數目下限。 @@ -883,11 +883,11 @@ The following test projects are using VSTest test runner: {0} See https://aka.ms/dotnet-test/mtp for more information. - global.json defines test runner to be Microsoft.Testing.Platform. All projects must use that test runner. -The following test projects are using VSTest test runner: + global.json 定義測試執行器為 Microsoft.Testing.Platform。所有專案必須使用該測試執行器。 +以下測試專案正在使用 VSTest 測試執行器: {0} -See https://aka.ms/dotnet-test/mtp for more information. +如需詳細資訊,請參閱 https://aka.ms/dotnet-test/mtp。 {Locked="global.json"}{Locked="Microsoft.Testing.Platform"} {0} is one or more project names. @@ -1128,7 +1128,7 @@ See https://aka.ms/dotnet-test/mtp for more information. error - error + 錯誤 Used when reporting directive errors like "file(location): error: message". @@ -1162,39 +1162,44 @@ See https://aka.ms/dotnet-test/mtp for more information. 正在以下位置找測試 - - .NET Test Command - .NET 測試命令 - + + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} + + + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. - Supported protocol versions sent by Microsoft.Testing.Platform are '{0}'. The SDK supports '{1}', which is incompatible. + Microsoft.Testing.Platform 所支援的通訊協定版本為 '{0}'。此 SDK 支援 '{1}',但兩者不相容。 Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. - Received 'ExecutionId' of value '{0}' for message '{1}' while the 'ExecutionId' received of the handshake message was '{2}'. + 收到訊息 '{1}' 的 'ExecutionId' 值為 '{0}',但交握訊息收到的 'ExecutionId' 為 '{2}'。 {Locked="ExecutionId"} Error disposing 'NamedPipeServer' corresponding to handshake: - Error disposing 'NamedPipeServer' corresponding to handshake: + 處理與交握對應的 'NamedPipeServer' 時發生錯誤: Error disposing 'NamedPipeServer', and no handshake was found. - Error disposing 'NamedPipeServer', and no handshake was found. + 處理 'NamedPipeServer' 時發生錯誤,且找不到交握。 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received less than 4 bytes from the 'dotnet test' named pipe. + 'dotnet' 從 'dotnet test' 具名管道意外接收到的資料少於 4 個位元組。 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. - 'dotnet' unexpectedly received overlapping messages from the 'dotnet test' named pipe. + 'dotnet' 從 'dotnet test' 具名管道意外接收到重疊訊息。 @@ -1228,14 +1233,24 @@ Make the profile names distinct. Duplicate directives are not supported: {0} - Duplicate directives are not supported: {0} + 不支援重複的指示詞: {0} {0} is the directive type and name. + + duration: + duration: + + + + error: + error: + + The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': {2} - The following exception occurred when running the test module with RunCommand '{0}' and RunArguments '{1}': + 使用 RunCommand '{0}' 和 RunArguments '{1}' 執行測試模組時,發生以下例外狀況: {2} {Locked="RunCommand"}{Locked="RunArguments"} @@ -1281,6 +1296,11 @@ Make the profile names distinct. 無法更新廣告資訊清單 {0}: {1}。 + + failed: + failed: + + failed 已失敗 @@ -1568,12 +1588,12 @@ Make the profile names distinct. Method '{0}' did not exit successfully - Method '{0}' did not exit successfully + 方法 '{0}' 未成功結束 The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. - The directive should contain a name without special characters and an optional value separated by '{1}' like '#:{0} Name{1}Value'. + 指示詞應包含不含特殊字元的名稱,以及 '{1}' 分隔的選用值,例如 '#:{0} Name{1}Value'。 {0} is the directive type like 'package' or 'sdk'. {1} is the expected separator like '@' or '='. @@ -1593,7 +1613,7 @@ Make the profile names distinct. The '#:project' directive is invalid: {0} - The '#:project' directive is invalid: {0} + '#:project' 指示詞無效: {0} {0} is the inner error message. @@ -1730,17 +1750,17 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. - A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + 測試應用程式收到新的交握 '{0}',與先前的交握 '{1}' 不相符。 Missing name of '{0}'. - Missing name of '{0}'. + 缺少 '{0}' 的名稱。 {0} is the directive name like 'package' or 'sdk'. A test session start event was received without a corresponding test session end. - A test session start event was received without a corresponding test session end. + 收到測試工作階段開始事件,但沒有對應的測試工作階段結束。 @@ -2502,12 +2522,12 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man Invalid property name: {0} - Invalid property name: {0} + 屬性名稱無效: {0} {0} is an inner exception message. The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. - The property directive needs to have two parts separated by '=' like '#:property PropertyName=PropertyValue'. + 屬性指示詞必須有兩個部分,其以 '=' 分隔,例如 '#:property PropertyName=PropertyValue'。 {Locked="#:property"} @@ -2552,6 +2572,11 @@ The default is to publish a framework-dependent application. 預設為發佈與 Framework 相依的應用程式。 + + Directives currently cannot contain double quotes ("). + Directives currently cannot contain double quotes ("). + + Shut down the Razor build server. 關閉 Razor 組建伺服器。 @@ -2672,6 +2697,11 @@ The default is to publish a framework-dependent application. 已還原工具 '{0}' (版本 '{1}')。可用的命令: {2} + + retried + retried + + Roll forward to framework version (LatestPatch, Minor, LatestMinor, Major, LatestMajor, Disable). 復原為架構版本 (LatestPatch、Minor、LatestMinor、Major、LatestMajor、Disable)。 @@ -2951,6 +2981,11 @@ Your project targets multiple frameworks. Specify which framework to run using ' 跳過建立符號檔,該檔案可用於分析最佳化組件。 + + skipped: + skipped: + + skipped 已跳過 @@ -3048,7 +3083,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' Static graph restore is not supported for file-based apps. Remove the '#:property'. - Static graph restore is not supported for file-based apps. Remove the '#:property'. + 檔案型應用程式不支援靜態圖表還原。移除 ''#:property'。 {Locked="#:property"} @@ -3086,6 +3121,11 @@ Your project targets multiple frameworks. Specify which framework to run using ' 要對其儲存套件的目標執行階段。 + + succeeded: + succeeded: + + Summary 摘要 @@ -3101,11 +3141,6 @@ Your project targets multiple frameworks. Specify which framework to run using ' 指定此命令的暫存目錄,以下載並解壓縮 NuGet 套件 (必須為安全)。 - - .NET Test Driver - .NET 測試驅動程式 - - + + total: + total: + + try {0} 嘗試 {0} @@ -3559,22 +3599,22 @@ and the corresponding package Ids for installed tools using the command An unexpected help-related message was received when `--help` wasn't used. - An unexpected help-related message was received when `--help` wasn't used. + 未使用 `--help` 時,收到未預期的說明相關訊息。 A message of type '{0}' was received in help mode, which is not expected. - A message of type '{0}' was received in help mode, which is not expected. + 在說明模式中收到類型為 '{0}' 的訊息,這是不預期的。 A message of type '{0}' was received before we got any handshakes, which is unexpected. - A message of type '{0}' was received before we got any handshakes, which is unexpected. + 在收到任何交握之前,我們就接收到類型為 '{0}' 的訊息,這是不預期的情況。 A test session end event was received without a corresponding test session start. - A test session end event was received without a corresponding test session start. + 收到測試工作階段結束事件,但沒有對應的測試工作階段開始。 @@ -3594,7 +3634,7 @@ and the corresponding package Ids for installed tools using the command Unrecognized directive '{0}'. - Unrecognized directive '{0}'. + 無法識別的指示詞 '{0}'。 {0} is the directive name like 'package' or 'sdk'. diff --git a/src/sdk/src/Cli/dotnet/CommonArguments.cs b/src/sdk/src/Cli/dotnet/CommonArguments.cs index 994444113cb..bef42994416 100644 --- a/src/sdk/src/Cli/dotnet/CommonArguments.cs +++ b/src/sdk/src/Cli/dotnet/CommonArguments.cs @@ -12,17 +12,23 @@ namespace Microsoft.DotNet.Cli internal class CommonArguments { public static DynamicArgument OptionalPackageIdentityArgument() => + OptionalPackageIdentityArgument("Newtonsoft.Json", "13.0.3"); + + public static DynamicArgument OptionalPackageIdentityArgument(string examplePackage, string exampleVersion) => new("packageId") { - Description = CliStrings.PackageIdentityArgumentDescription, + Description = string.Format(CliStrings.PackageIdentityArgumentDescription, examplePackage, exampleVersion), CustomParser = (ArgumentResult argumentResult) => ParsePackageIdentityWithVersionSeparator(argumentResult.Tokens[0]?.Value), Arity = ArgumentArity.ZeroOrOne, }; public static DynamicArgument RequiredPackageIdentityArgument() => + RequiredPackageIdentityArgument("Newtonsoft.Json", "13.0.3"); + + public static DynamicArgument RequiredPackageIdentityArgument(string examplePackage, string exampleVersion) => new("packageId") { - Description = CliStrings.PackageIdentityArgumentDescription, + Description = string.Format(CliStrings.PackageIdentityArgumentDescription, examplePackage, exampleVersion), CustomParser = (ArgumentResult argumentResult) => ParsePackageIdentityWithVersionSeparator(argumentResult.Tokens[0]?.Value)!.Value, Arity = ArgumentArity.ExactlyOne, }; diff --git a/src/sdk/src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs b/src/sdk/src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs index 8ac89af4021..a311e88c646 100644 --- a/src/sdk/src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs +++ b/src/sdk/src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs @@ -4,9 +4,11 @@ #nullable disable using System.Collections.Concurrent; +using Microsoft.DotNet.Cli.Extensions; using Microsoft.DotNet.Cli.NugetPackageDownloader; using Microsoft.DotNet.Cli.ToolPackage; using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Cli.Utils.Extensions; using Microsoft.Extensions.EnvironmentAbstractions; using NuGet.Common; using NuGet.Configuration; @@ -450,9 +452,21 @@ public IEnumerable LoadNuGetSources(PackageId packageId, PackageS throw new NuGetPackageInstallerException("No NuGet sources are defined or enabled"); } + CheckHttpSources(sources); return sources; } + private void CheckHttpSources(IEnumerable packageSources) + { + foreach (var packageSource in packageSources) + { + if (packageSource.IsHttp && !packageSource.IsHttps && !packageSource.AllowInsecureConnections) + { + throw new NuGetPackageInstallerException(string.Format(CliStrings.Error_NU1302_HttpSourceUsed, packageSource.Source)); + } + } + } + private async Task<(PackageSource, IPackageSearchMetadata)> GetMatchingVersionInternalAsync( string packageIdentifier, IEnumerable packageSources, VersionRange versionRange, CancellationToken cancellationToken) diff --git a/src/sdk/src/Cli/dotnet/Program.cs b/src/sdk/src/Cli/dotnet/Program.cs index ea6537b4151..e57fe3a5635 100644 --- a/src/sdk/src/Cli/dotnet/Program.cs +++ b/src/sdk/src/Cli/dotnet/Program.cs @@ -6,6 +6,7 @@ using System.CommandLine; using System.CommandLine.Parsing; using System.Diagnostics; +using System.Runtime.InteropServices; using Microsoft.DotNet.Cli.CommandFactory; using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; using Microsoft.DotNet.Cli.Commands.Run; @@ -29,6 +30,10 @@ public class Program public static ITelemetry TelemetryClient; public static int Main(string[] args) { + // Register a handler for SIGTERM to allow graceful shutdown of the application on Unix. + // See https://github.com/dotnet/docs/issues/46226. + using var termSignalRegistration = PosixSignalRegistration.Create(PosixSignal.SIGTERM, _ => Environment.Exit(0)); + using AutomaticEncodingRestorer _ = new(); // Setting output encoding is not available on those platforms @@ -235,10 +240,7 @@ internal static int ProcessArgs(string[] args, TimeSpan startupTime) if (TelemetryClient.Enabled) { // Get the global.json state to report in telemetry along with this command invocation. - // We don't care about the actual SDK resolution, just the global.json information, - // so just pass empty string as executable directory for resolution. - // NativeWrapper.SdkResolutionResult result = NativeWrapper.NETCoreSdkResolverNativeWrapper.ResolveSdk(string.Empty, Environment.CurrentDirectory); - // globalJsonState = result.GlobalJsonState; + globalJsonState = NativeWrapper.NETCoreSdkResolverNativeWrapper.GetGlobalJsonState(Environment.CurrentDirectory); } TelemetryEventEntry.SendFiltered(Tuple.Create(parseResult, performanceData, globalJsonState)); diff --git a/src/sdk/src/Cli/dotnet/Telemetry/EnvironmentDetectionRule.cs b/src/sdk/src/Cli/dotnet/Telemetry/EnvironmentDetectionRule.cs index 5cd73f53abb..ebdf6321ddd 100644 --- a/src/sdk/src/Cli/dotnet/Telemetry/EnvironmentDetectionRule.cs +++ b/src/sdk/src/Cli/dotnet/Telemetry/EnvironmentDetectionRule.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Cli.Telemetry; @@ -33,8 +34,7 @@ public BooleanEnvironmentRule(params string[] variables) public override bool IsMatch() { - return _variables.Any(variable => - bool.TryParse(Environment.GetEnvironmentVariable(variable), out bool value) && value); + return _variables.Any(variable => Env.GetEnvironmentVariableAsBool(variable)); } } @@ -81,12 +81,12 @@ public override bool IsMatch() /// The type of the result value. internal class EnvironmentDetectionRuleWithResult where T : class { - private readonly string[] _variables; + private readonly EnvironmentDetectionRule _rule; private readonly T _result; - public EnvironmentDetectionRuleWithResult(T result, params string[] variables) + public EnvironmentDetectionRuleWithResult(T result, EnvironmentDetectionRule rule) { - _variables = variables ?? throw new ArgumentNullException(nameof(variables)); + _rule = rule ?? throw new ArgumentNullException(nameof(rule)); _result = result ?? throw new ArgumentNullException(nameof(result)); } @@ -96,8 +96,8 @@ public EnvironmentDetectionRuleWithResult(T result, params string[] variables) /// The result value if the rule matches; otherwise, null. public T? GetResult() { - return _variables.Any(variable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable(variable))) - ? _result + return _rule.IsMatch() + ? _result : null; } -} \ No newline at end of file +} diff --git a/src/sdk/src/Cli/dotnet/Telemetry/ILLMEnvironmentDetector.cs b/src/sdk/src/Cli/dotnet/Telemetry/ILLMEnvironmentDetector.cs index fe599569aa6..e2ee2159156 100644 --- a/src/sdk/src/Cli/dotnet/Telemetry/ILLMEnvironmentDetector.cs +++ b/src/sdk/src/Cli/dotnet/Telemetry/ILLMEnvironmentDetector.cs @@ -5,5 +5,13 @@ namespace Microsoft.DotNet.Cli.Telemetry; internal interface ILLMEnvironmentDetector { + /// + /// Checks the current environment for known indicators of LLM usage and returns a string identifying the LLM environment if detected. + /// string? GetLLMEnvironment(); -} \ No newline at end of file + + /// + /// Returns true if the current environment is detected to be an LLM/agentic environment, false otherwise. + /// + bool IsLLMEnvironment(); +} diff --git a/src/sdk/src/Cli/dotnet/Telemetry/LLMEnvironmentDetectorForTelemetry.cs b/src/sdk/src/Cli/dotnet/Telemetry/LLMEnvironmentDetectorForTelemetry.cs index 16d13a6879e..b37f9b5d083 100644 --- a/src/sdk/src/Cli/dotnet/Telemetry/LLMEnvironmentDetectorForTelemetry.cs +++ b/src/sdk/src/Cli/dotnet/Telemetry/LLMEnvironmentDetectorForTelemetry.cs @@ -1,23 +1,30 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Linq; - namespace Microsoft.DotNet.Cli.Telemetry; internal class LLMEnvironmentDetectorForTelemetry : ILLMEnvironmentDetector { private static readonly EnvironmentDetectionRuleWithResult[] _detectionRules = [ // Claude Code - new EnvironmentDetectionRuleWithResult("claude", "CLAUDECODE"), + new EnvironmentDetectionRuleWithResult("claude", new AnyPresentEnvironmentRule("CLAUDECODE")), // Cursor AI - new EnvironmentDetectionRuleWithResult("cursor", "CURSOR_EDITOR") + new EnvironmentDetectionRuleWithResult("cursor", new AnyPresentEnvironmentRule("CURSOR_EDITOR")), + // Gemini + new EnvironmentDetectionRuleWithResult("gemini", new BooleanEnvironmentRule("GEMINI_CLI")), + // GitHub Copilot + new EnvironmentDetectionRuleWithResult("copilot", new BooleanEnvironmentRule("GITHUB_COPILOT_CLI_MODE")), + // (proposed) generic flag for Agentic usage + new EnvironmentDetectionRuleWithResult("generic_agent", new BooleanEnvironmentRule("AGENT_CLI")), ]; + /// public string? GetLLMEnvironment() { var results = _detectionRules.Select(r => r.GetResult()).Where(r => r != null).ToArray(); return results.Length > 0 ? string.Join(", ", results) : null; } -} \ No newline at end of file + + /// + public bool IsLLMEnvironment() => !string.IsNullOrEmpty(GetLLMEnvironment()); +} diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.cs.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.cs.xlf index 8c527843628..793563fbddd 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.cs.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.cs.xlf @@ -100,14 +100,14 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + Nastavuje hodnotu proměnné prostředí. +Pokud proměnná neexistuje, vytvoří ji, a pokud existuje, přepíše ji. +Tento argument je možné zadat vícekrát a určit tak více proměnných. Examples: -e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" +-e VARIABLE="hodnota s mezerami" +-e VARIABLE="hodnota;oddělená;pomocí;středníků" -e VAR1=abc -e VAR2=def -e VAR3=ghi @@ -129,16 +129,16 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + Nastaví hodnotu proměnné prostředí. +Pokud proměnná neexistuje, vytvoří ji, a pokud existuje, přepíše ji. +Tímto se vynutí spuštění testů v izolovaném procesu. +Tento argument je možné zadat vícekrát a určit tak více proměnných. -Examples: --e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" --e VAR1=abc -e VAR2=def -e VAR3=ghi +Příklady: +-e PROMĚNNÁ=abc +-e PROMĚNNÁ="hodnota s mezerami" +-e PROMĚNNÁ="hodnota;oddělená;pomocí;středníků" +-e PROM1=abc -e PROM2=def -e PROM3=ghi @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" Chyba + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + Spouštíte operaci instalace nástroje se zdrojem HTTP: {0}. NuGet vyžaduje zdroje HTTPS. Pokud chcete použít zdroj HTTP, musíte v souboru NuGet.Config explicitně nastavit možnost allowInsecureConnections na true. Další informace najdete na https://aka.ms/nuget-https-everywhere. + + {0}: expect deps.json at: {1} {0}: Soubor deps.json se očekává v: {1} @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - Odkaz na balíček ve formě identifikátoru balíčku, jako je Newtonsoft.Json, nebo identifikátor balíčku a verze oddělené znakem @, například Newtonsoft.Json@13.0.3. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.de.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.de.xlf index 491f30dc0ea..75a8ea0992b 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.de.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.de.xlf @@ -100,14 +100,14 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + Legt den Wert einer Umgebungsvariablen fest. +Erstellt die Variable, wenn Sie nicht vorhanden ist, und setzt sie andernfalls außer Kraft. +Dieses Argument kann mehrmals angegeben werden, um mehrere Variablen bereitzustellen. -Examples: +Beispiele: -e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" +-e VARIABLE="wert mit leerzeichen" +-e VARIABLE="wert;getrennt durch;semikolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi @@ -129,15 +129,15 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + Legt den Wert einer Umgebungsvariablen fest. +Erstellt die Variable, wenn Sie nicht vorhanden ist, und setzt sie andernfalls außer Kraft. +Dadurch wird die Ausführung der Tests in einem isolierten Prozess erzwungen. +Dieses Argument kann mehrmals angegeben werden, um mehrere Variablen bereitzustellen. -Examples: +Beispiele: -e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" +-e VARIABLE="wert mit leerzeichen" +-e VARIABLE="wert;getrennt durch;semikolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" Fehler + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + Sie führen den Toolinstallationsvorgang mit einer HTTP-Quelle aus: {0}. NuGet erfordert HTTPS-Quellen. Um eine HTTP-Quelle zu verwenden, müssen Sie „allowInsecureConnections“ in Ihrer NuGet.Config-Datei explizit auf TRUE festlegen. Weitere Informationen finden Sie unter https://aka.ms/nuget-https-everywhere. + + {0}: expect deps.json at: {1} {0}: "deps.json" vermutet unter: {1} @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - Paketverweis in Form eines Paketbezeichners wie "Newtonsoft.Json" oder Paketbezeichner und -version getrennt durch "@" wie "Newtonsoft.Json@13.0.3". + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.es.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.es.xlf index 5b0099211e6..e1598973152 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.es.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.es.xlf @@ -100,11 +100,11 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + Establece el valor de una variable de entorno. +Crea la variable si no existe o la reemplaza en caso de que exista. +Este argumento se puede especificar varias veces para proporcionar múltiples variables. -Examples: +Ejemplos: -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -129,12 +129,12 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + Establece el valor de una variable de entorno. +Crea la variable si no existe o la reemplaza en caso de que exista. +Esto forzará la ejecución de las pruebas en un proceso aislado. +Este argumento se puede especificar varias veces para proporcionar múltiples variables. -Examples: +Ejemplos: -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" Error + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + Está ejecutando la operación "tool install" con un origen "HTTP", {0}. NuGet requiere orígenes HTTPS. Para usar un origen HTTP, es necesario establecer explícitamente "allowInsecureConnections" en true en el archivo NuGet.Config. Consulte https://aka.ms/nuget-https-everywhere para obtener más información. + + {0}: expect deps.json at: {1} {0}: se espera deps.json en: {1} @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - Referencia de paquete en forma de identificador de paquete como "Newtonsoft.Json" o identificador de paquete y versión separados por "@", como "Newtonsoft.Json@13.0.3". + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.fr.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.fr.xlf index 4ee02305143..c559d991fdb 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.fr.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.fr.xlf @@ -100,11 +100,11 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + Définit la valeur d’une variable d’environnement. +Crée la variable si elle n’existe pas, et la remplace si elle existe. +Vous pouvez spécifier cet argument plusieurs fois pour fournir plusieurs variables. -Examples: +Exemples : -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -129,15 +129,15 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + Définit la valeur d'une variable d'environnement. +Crée la variable si elle n'existe pas, et la remplace si elle existe. +Cela entraîne l'exécution forcée des tests dans un processus isolé. +Vous pouvez spécifier cet argument plusieurs fois pour fournir plusieurs variables. -Examples: +Exemples : -e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" +-e VARIABLE="valeur avec des espaces" +-e VARIABLE="valeur;séparée;par;des;points;virgules" -e VAR1=abc -e VAR2=def -e VAR3=ghi @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" Erreur + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + Vous exécutez l'opération « installation d’outils » avec une source « HTTP » : {0}. NuGet nécessite des sources HTTPS. Pour utiliser une source HTTP, vous devez définir explicitement « allowInsecureConnections » sur true dans votre fichier NuGet.Config. Reportez-vous à https://aka.ms/nuget-https-everywhere pour plus d’informations. + + {0}: expect deps.json at: {1} {0} : deps.json attendu sur {1} @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - Référence de package sous la forme d’un identificateur de package tel que « Newtonsoft.Json » ou d’un identificateur de package et d’une version séparés par « @ », comme « Newtonsoft.Json@13.0.3 ». + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.it.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.it.xlf index 25f463a93e0..632432b2b28 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.it.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.it.xlf @@ -100,14 +100,14 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + Imposta il valore di una variabile di ambiente. +Crea la variabile se non esiste e la sostituisce se esiste. +È possibile specificare più volte l'argomento per fornire più variabili. -Examples: +Esempi: -e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" +-e VARIABLE="valore con spazi" +-e VARIABLE="valore;delimitato da;punti e virgola" -e VAR1=abc -e VAR2=def -e VAR3=ghi @@ -129,15 +129,15 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + Imposta il valore di una variabile di ambiente. +Crea la variabile se non esiste e la sostituisce se esiste. +In questo modo forza l'esecuzione dei test in un processo isolato. +È possibile specificare più volte questo argomento per fornire più variabili. -Examples: +Esempi: -e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" +-e VARIABLE="valore con spazi" +-e VARIABLE="valore;delimitato da;punti e virgola" -e VAR1=abc -e VAR2=def -e VAR3=ghi @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" Errore + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + L'operazione 'tool install' è in esecuzione con un'origine 'HTTP': {0}. NuGet richiede origini HTTPS. Per usare un’origine HTTP, è necessario impostare in modo esplicito ‘allowInsecureConnections’ su true nel file NuGet.Config. Vedere https://aka.ms/nuget-https-everywhere per altre informazioni. + + {0}: expect deps.json at: {1} {0}: è previsto deps.json in: {1} @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - Riferimento al pacchetto sotto forma di identificatore di pacchetto, ad esempio 'Newtonsoft.Json', oppure identificatore e versione di pacchetto separati da '@', ad esempio 'Newtonsoft.Json@13.0.3'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ja.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ja.xlf index 929c69303fc..4ec60d0c7ee 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ja.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ja.xlf @@ -100,11 +100,11 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + 環境変数の値を設定します。 +変数が存在しない場合は作成され、存在する場合はオーバーライドされます。 +この引数は、複数の変数を指定するために複数回指定できます。 -Examples: +例: -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -129,12 +129,12 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + 環境変数の値を設定します。 +変数が存在しない場合は作成され、存在する場合はオーバーライドされます。 +これにより、テストは強制的に分離プロセスで実行されます。 +この引数は、複数の変数を指定するために複数回指定できます。 -Examples: +例: -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" エラー + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + 'tool install' 操作を、HTTP ソース {0} を使用して実行しています。NuGet には HTTPS ソースが必要です。HTTP ソースを使用するには、NuGet.Config ファイルで 'allowInsecureConnections' を true に明示的に設定する必要があります。詳しくは、https://aka.ms/nuget-https-everywhere を参照してください。 + + {0}: expect deps.json at: {1} {0}: {1} で deps.json が必要です @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - 'Newtonsoft.Json' のようなパッケージ識別子の形式のパッケージ参照、または 'Newtonsoft.Json@13.0.3' のような '@' で区切られたパッケージ識別子とバージョンです。 + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ko.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ko.xlf index 70f1a461e3e..c65066c2341 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ko.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ko.xlf @@ -100,11 +100,11 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + 환경 변수의 값을 설정합니다. +변수가 없는 경우 변수를 만들고, 변수가 있으면 재정의합니다. +이 인수를 여러 번 지정하여 여러 변수를 제공할 수 있습니다. -Examples: +예: -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -129,12 +129,12 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + 환경 변수의 값을 설정합니다. +변수가 없는 경우 변수를 만들고, 변수가 있으면 재정의합니다. +이는 테스트가 격리된 프로세스에서 강제로 실행되도록 합니다. +이 인수를 여러 번 지정하여 여러 변수를 제공할 수 있습니다. -Examples: +예: -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" 오류 + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + 여러분은 'tool install' 작업을 'HTTP' 원본 {0}(으)로 실행하고 있습니다. NuGet에는 HTTPS 원본이 필요합니다. HTTP 원본을 사용하려면 NuGet.Config 파일에서 'allowInsecureConnections'를 명시적으로 true로 설정해야 합니다. https://aka.ms/nuget-https-everywhere에서 자세한 내용을 참조하세요. + + {0}: expect deps.json at: {1} {0}: {1}에서 deps.json 필요 @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - 'Newtonsoft.Json'과 같은 패키지 식별자 또는 'Newtonsoft.Json@13.0.3'과 같이 '@'로 구분된 패키지 식별자 및 버전 형식의 패키지 참조입니다. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.pl.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.pl.xlf index ab822597d6b..47183ec7a67 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.pl.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.pl.xlf @@ -100,15 +100,15 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + Ustawia wartość zmiennej środowiskowej. +Jeśli zmienna nie istnieje, tworzy ją, a jeśli istnieje, przesłania. +Ten argument można określić wiele razy w celu podania wielu wartości. -Examples: --e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" --e VAR1=abc -e VAR2=def -e VAR3=ghi +Przykłady: +-e ZMIENNA=abc +-e ZMIENNA=”wartość ze spacjami” +-e ZMIENNA=”wartości;rozdzielone;średnikami” +-e ZM1=abc -e ZM2=def -e ZM3=ghi @@ -129,16 +129,16 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + Ustawia wartość zmiennej środowiskowej. +Jeśli zmienna nie istnieje, tworzy ją, a jeśli istnieje, przesłania. +Wymusi to uruchamianie testów w izolowanym procesie. +Ten argument można określić wiele razy w celu podania wielu wartości. -Examples: --e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" --e VAR1=abc -e VAR2=def -e VAR3=ghi +Przykłady: +-e ZMIENNA=abc +-e ZMIENNA="wartość ze spacjami" +-e ZMIENNA="wartości;rozdzielone;średnikami" +-e ZM1=abc -e ZM2=def -e ZM3=ghi @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" Błąd + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + Operację „instalacji narzędzia” wykonujesz ze źródłem „HTTP”: {0}. Menedżer NuGet wymaga źródeł HTTPS. Aby użyć źródła HTTP, musisz wyraźnie ustawić właściwość „allowInsecureConnections” na wartość true w pliku NuGet.Config. Aby uzyskać więcej informacji, sprawdź witrynę https://aka.ms/nuget-https-everywhere. + + {0}: expect deps.json at: {1} {0}: Oczekiwano pliku deps.json w lokalizacji: {1} @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - Odwołanie do pakietu w postaci identyfikatora pakietu, takiego jak „Newtonsoft.Json” lub identyfikator pakietu i wersja rozdzielone znakiem „@”, na przykład „Newtonsoft.Json@13.0.3”. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf index 1fb89af5253..fccf80013c6 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf @@ -100,14 +100,14 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + Define o valor de uma variável de ambiente. +Cria a variável se ela não existir, substitui se existir. +Este argumento pode ser especificado várias vezes para fornecer múltiplas variáveis. -Examples: +Exemplos: -e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" +-e VARIABLE="valor com espaços" +-e VARIABLE="valor;separado com;ponto e vírgula" -e VAR1=abc -e VAR2=def -e VAR3=ghi @@ -129,15 +129,15 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + Define o valor de uma variável de ambiente. +Criará a variável quando ela não existir e a substituirá quando existir. +Isso forçará a execução dos testes em um processo isolado. +Esse argumento pode ser especificado várias vezes para fornecer várias variáveis. -Examples: +Exemplos: -e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" +-e VARIABLE="valor com espaços" +-e VARIABLE="valor;separado com;ponto e vírgula" -e VAR1=abc -e VAR2=def -e VAR3=ghi @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" Erro + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + Você está executando a operação 'tool install' com uma fonte 'HTTP': {0}. O NuGet requer fontes HTTPS. Para usar uma fonte HTTP, você deve definir explicitamente 'allowInsecureConnections' como true no arquivo NuGet.Config. Consulte https://aka.ms/nuget-https-everywhere para mais informações. + + {0}: expect deps.json at: {1} {0}: espera de deps.json em: {1} @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - Referência do pacote na forma de um identificador de pacote como 'Newtonsoft.Json' ou identificador e versão do pacote separados por '@', como 'Newtonsoft.Json\@13.0.3'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ru.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ru.xlf index 73edbd77fff..3814f20f1ca 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ru.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ru.xlf @@ -100,14 +100,14 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + Устанавливает значение переменной среды. +Если переменной среды не существует, она создается, если существует — переопределяется. +Этот аргумент может быть указан несколько раз для указания нескольких переменных. -Examples: +Примеры: -e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" +-e VARIABLE="значение с пробелами" +-e VARIABLE="значение;разделенное;точками;с;запятыми" -e VAR1=abc -e VAR2=def -e VAR3=ghi @@ -129,15 +129,15 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + Устанавливает значение переменной среды. +Если переменной среды не существует, она создается. Если переменная среды существует, она переопределяется. +Этот аргумент подразумевает принудительное выполнение тестов в изолированном процессе. +Этот аргумент может быть указан несколько раз для нескольких переменных среды. -Examples: +Примеры: -e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" +-e VARIABLE="значение с пробелами" +-e VARIABLE="значение;разделенное;точками;с;запятыми" -e VAR1=abc -e VAR2=def -e VAR3=ghi @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" Ошибка + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + Вы выполняете операцию "установка средства" с источником "HTTP": {0}. Для NuGet требуются источники HTTPS. Чтобы использовать источник HTTP, необходимо явно задать для параметра "allowInsecureConnections" значение true в файле NuGet.Config. Дополнительные сведения см. на странице https://aka.ms/nuget-https-everywhere. + + {0}: expect deps.json at: {1} {0}: ожидается deps.json в: {1}. @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - Ссылка на пакет в виде идентификатора пакета, например "Newtonsoft.Json", или идентификатора пакета и версии, разделенных "@", например "Newtonsoft.Json@13.0.3". + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.tr.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.tr.xlf index 162ee49cbd8..e6dc0a5df79 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.tr.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.tr.xlf @@ -100,15 +100,15 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + Bir ortam değişkeninin değerini ayarlar. +Değişken yoksa oluşturur, varsa değişkeni geçersiz kılar. +Bu bağımsız değişken, birden çok değişken sağlamak için birden çok kez belirtilebilir. -Examples: --e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" --e VAR1=abc -e VAR2=def -e VAR3=ghi +Örnek: +-e DEĞİŞKEN=abc +-e DEĞİŞKEN="boşluk içeren değerler" +-e DEĞİŞKEN="noktalı virgülle;ayrılmış;değerler" +-e DEĞ1=abc -e DEĞ2=def -e DEĞ3=ghi @@ -129,16 +129,16 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + Bir ortam değişkeninin değerini ayarlar. +Değişken yoksa oluşturur, varsa değişkeni geçersiz kılar. +Bu, testleri yalıtılmış bir işlemde çalıştırılmaya zorlar. +Bu bağımsız değişken, birden çok değişken sağlamak için birden çok kez belirtilebilir. -Examples: --e VARIABLE=abc --e VARIABLE="value with spaces" --e VARIABLE="value;seperated with;semicolons" --e VAR1=abc -e VAR2=def -e VAR3=ghi +Örnek: +-e DEĞİŞKEN=abc +-e DEĞİŞKEN="boşluk içeren değerler" +-e DEĞİŞKEN="noktalı virgülle;ayrılmış;değerler" +-e DEĞ1=abc -e DEĞ2=def -e DEĞ3=ghi @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" Hata + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + 'tool install' işlemini {0} 'HTTP' kaynağıyla çalıştırıyorsunuz. NuGet için HTTPS kaynakları gereklidir. Bir HTTP kaynağı kullanmak için NuGet.Config dosyanızda 'allowInsecureConnections' ayarını açıkça true olarak ayarlamanız gerekir. Daha fazla bilgi için şuraya bakın: https://aka.ms/nuget-https-everywhere. + + {0}: expect deps.json at: {1} {0}: şu konumda deps.json bekleniyor: {1} @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - 'Newtonsoft.Json' gibi bir paket tanımlayıcısı veya 'Newtonsoft.Json@13.0.3' gibi '@' ile ayrılmış paket tanımlayıcısı ve sürümü şeklinde paket referansı. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf index d32b2f7bcba..7dc1e93e52e 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf @@ -100,11 +100,11 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + 设置环境变量的值。 +如果该变量不存在,则创建它; 如果它已存在,则替代它。 +可多次指定此参数来提供多个变量。 -Examples: +示例: -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -129,12 +129,12 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + 设置环境变量的值。 +如果该变量不存在,则创建它;如果它已存在,则替代它。 +这将在隔离的进程中强制运行测试。 +可多次指定此参数来提供多个变量。 -Examples: +示例: -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" 错误 + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + 正在通过 "HTTP" 源运行“工具安装”操作: {0}。NuGet 需要 HTTPS 源。要使用 HTTP 源,必须在 NuGet.Config 文件中将 "allowInsecureConnections" 显式设置为 true。有关详细信息,请参阅 https://aka.ms/nuget-https-everywhere。 + + {0}: expect deps.json at: {1} {0}: 需要 deps.json: {1} @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - 包引用采用包标识符形式,如 'Newtonsoft.Json',或采用以 ‘@’ 分隔包标识符和版本的形式,如 ‘Newtonsoft.Json@13.0.3’。 + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf index 0009d535cc3..bd3384fb806 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf @@ -100,11 +100,11 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This argument can be specified multiple times to provide multiple variables. + 設定環境變數的值。 +若變數不存在,則加以建立; 若有,則予以覆寫。 +此引數可多次指定,以提供多項變數。 -Examples: +範例: -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -129,12 +129,12 @@ Examples: -e VARIABLE="value;seperated with;semicolons" -e VAR1=abc -e VAR2=def -e VAR3=ghi - Sets the value of an environment variable. -Creates the variable if it does not exist, overrides if it does. -This will force the tests to be run in an isolated process. -This argument can be specified multiple times to provide multiple variables. + 設定環境變數的值。 +若變數不存在,則加以建立; 若有,則予以覆寫。 +這會強制在隔離流程中執行測試。 +此引數可多次指定,以提供多項變數。 -Examples: +範例: -e VARIABLE=abc -e VARIABLE="value with spaces" -e VARIABLE="value;seperated with;semicolons" @@ -372,6 +372,11 @@ setx PATH "%PATH%;{0}" 錯誤 + + You are running the 'tool install' operation with an 'HTTP' source: {0}. NuGet requires HTTPS sources. To use an HTTP source, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. + 您正使用 'HTTP' 來源執行 'tool install' 作業: {0}。NuGet 需要 HTTPS 來源。若要使用 HTTP 來源,您必須在 NuGet.Config 檔案中將 'allowInsecureConnections' 明確設定為 true。如需詳細資訊,請參閱 https://aka.ms/nuget-https-everywhere。 + + {0}: expect deps.json at: {1} {0}: 於 {1} 需要 deps.json @@ -778,8 +783,8 @@ setx PATH "%PATH%;{0}" - Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. - 套件參考的格式為套件識別碼,例如 'Newtonsoft.Json',或是以 '@' 分隔的套件識別碼和版本,例如 'Newtonsoft.Json@13.0.3'。 + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. diff --git a/src/sdk/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj b/src/sdk/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj index bb4234adee1..d0a01f20c9c 100644 --- a/src/sdk/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj +++ b/src/sdk/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj @@ -1,4 +1,4 @@ - + net472 @@ -21,6 +21,7 @@ $(ArtifactsNonShippingPackagesDir)VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.swr + $(OutputPath)\metadata.json @@ -35,21 +36,51 @@ + - + + %(RecursiveDir) + + + %(RecursiveDir) + + + + + + + + + + + + <_VsixNamespace> + + + + + + - + + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1028/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1028/bundle.wxl index d5dab6739e8..96ae1777e64 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1028/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1028/bundle.wxl @@ -75,7 +75,7 @@ - + @@ -87,7 +87,7 @@ - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1029/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1029/bundle.wxl index 055fca9625d..8996b6dba4d 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1029/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1029/bundle.wxl @@ -75,7 +75,7 @@ Tento produkt shromažďuje data o využití - + @@ -87,7 +87,7 @@ Tento produkt shromažďuje data o využití - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1031/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1031/bundle.wxl index 580ff66ccaf..33bf3763a24 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1031/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1031/bundle.wxl @@ -75,7 +75,7 @@ Dieses Produkt sammelt Verbrauchsdaten - + @@ -87,7 +87,7 @@ Dieses Produkt sammelt Verbrauchsdaten - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1036/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1036/bundle.wxl index a37224b9b43..ca3e7b265f7 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1036/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1036/bundle.wxl @@ -75,7 +75,7 @@ Ce produit collecte des données d’utilisation - + @@ -87,7 +87,7 @@ Ce produit collecte des données d’utilisation - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1040/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1040/bundle.wxl index 93ddcb272ea..aab082f8ac2 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1040/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1040/bundle.wxl @@ -75,7 +75,7 @@ Questo prodotto raccoglie i dati di utilizzo - + @@ -87,7 +87,7 @@ Questo prodotto raccoglie i dati di utilizzo - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1041/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1041/bundle.wxl index 1443af39d34..cda559ded66 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1041/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1041/bundle.wxl @@ -75,7 +75,7 @@ - + @@ -87,7 +87,7 @@ - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1042/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1042/bundle.wxl index c62a7d6f40b..754a45fe369 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1042/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1042/bundle.wxl @@ -75,7 +75,7 @@ - + @@ -87,7 +87,7 @@ - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1045/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1045/bundle.wxl index 459fb7b00c0..9ab2050a67e 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1045/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1045/bundle.wxl @@ -75,7 +75,7 @@ Ten produkt zbiera dane użycia - + @@ -87,7 +87,7 @@ Ten produkt zbiera dane użycia - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1046/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1046/bundle.wxl index 0fd102845e5..f8f517f4395 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1046/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1046/bundle.wxl @@ -75,7 +75,7 @@ Esse produto coleta dados de uso - + @@ -87,7 +87,7 @@ Esse produto coleta dados de uso - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1049/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1049/bundle.wxl index f4d85a5d46f..59c961fbdd8 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1049/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1049/bundle.wxl @@ -75,7 +75,7 @@ - + @@ -87,7 +87,7 @@ - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1055/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1055/bundle.wxl index e3c1b1c82d8..0c25970fd44 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1055/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/1055/bundle.wxl @@ -75,7 +75,7 @@ Bu ürün, kullanım verilerini toplar - + @@ -87,7 +87,7 @@ Bu ürün, kullanım verilerini toplar - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/2052/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/2052/bundle.wxl index 092b8a3e374..4b5b8b92809 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/2052/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/2052/bundle.wxl @@ -75,7 +75,7 @@ - + @@ -87,7 +87,7 @@ - + diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/3082/bundle.wxl b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/3082/bundle.wxl index 2b2f012b279..084aa9dbf0a 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/3082/bundle.wxl +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/LCID/3082/bundle.wxl @@ -75,7 +75,7 @@ Este producto recopila datos de uso - + @@ -87,7 +87,7 @@ Este producto recopila datos de uso - + diff --git a/src/sdk/src/Layout/redist/redist.csproj b/src/sdk/src/Layout/redist/redist.csproj index 803a0334f54..22d3827eab4 100644 --- a/src/sdk/src/Layout/redist/redist.csproj +++ b/src/sdk/src/Layout/redist/redist.csproj @@ -29,7 +29,7 @@ - + diff --git a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.CSharp.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/CSharpDetectPreviewFeatureAnalyzer.cs b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.CSharp.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/CSharpDetectPreviewFeatureAnalyzer.cs index 849b35e3b4a..2ab9ff66301 100644 --- a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.CSharp.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/CSharpDetectPreviewFeatureAnalyzer.cs +++ b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.CSharp.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/CSharpDetectPreviewFeatureAnalyzer.cs @@ -2,9 +2,12 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using Analyzer.Utilities.Lightup; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; using Microsoft.NetCore.Analyzers.Runtime; namespace Microsoft.NetCore.CSharp.Analyzers.Runtime @@ -12,6 +15,17 @@ namespace Microsoft.NetCore.CSharp.Analyzers.Runtime [DiagnosticAnalyzer(LanguageNames.CSharp)] public class CSharpDetectPreviewFeatureAnalyzer : DetectPreviewFeatureAnalyzer { + protected override ISymbol? SymbolFromAwaitOperation(IAwaitOperation operation) + { + if (operation.Syntax is not AwaitExpressionSyntax awaitSyntax) + { + return null; + } + + var awaitableInfo = operation.SemanticModel.GetAwaitExpressionInfo(awaitSyntax); + return awaitableInfo.RuntimeAwaitMethod; + } + protected override SyntaxNode? GetPreviewSyntaxNodeForFieldsOrEvents(ISymbol fieldOrEventSymbol, ISymbol previewSymbol) { ImmutableArray fieldOrEventReferences = fieldOrEventSymbol.DeclaringSyntaxReferences; diff --git a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureAnalyzer.cs b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureAnalyzer.cs index 52f86e75631..1df63a6f732 100644 --- a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureAnalyzer.cs +++ b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureAnalyzer.cs @@ -269,7 +269,8 @@ public override void Initialize(AnalysisContext context) OperationKind.ArrayCreation, OperationKind.CatchClause, OperationKind.TypeOf, - OperationKind.EventAssignment + OperationKind.EventAssignment, + OperationKind.Await ); // Handle preview symbol definitions @@ -809,7 +810,7 @@ private bool OperationUsesPreviewFeatures(OperationAnalysisContext context, return false; } - private static ISymbol? GetOperationSymbol(IOperation operation) + private ISymbol? GetOperationSymbol(IOperation operation) => operation switch { IInvocationOperation iOperation => iOperation.TargetMethod, @@ -824,6 +825,7 @@ private bool OperationUsesPreviewFeatures(OperationAnalysisContext context, ICatchClauseOperation catchClauseOperation => catchClauseOperation.ExceptionType, ITypeOfOperation typeOfOperation => typeOfOperation.TypeOperand, IEventAssignmentOperation eventAssignment => GetOperationSymbol(eventAssignment.EventReference), + IAwaitOperation awaitOperation => SymbolFromAwaitOperation(awaitOperation), _ => null, }; @@ -838,6 +840,8 @@ private bool OperationUsesPreviewFeatures(OperationAnalysisContext context, return ret; } + protected abstract ISymbol? SymbolFromAwaitOperation(IAwaitOperation operation); + private bool TypeParametersHavePreviewAttribute(ISymbol namedTypeSymbolOrMethodSymbol, ImmutableArray typeParameters, ConcurrentDictionary requiresPreviewFeaturesSymbols, diff --git a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/BasicDetectPreviewFeatureAnalyzer.vb b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/BasicDetectPreviewFeatureAnalyzer.vb index e357049f7d5..be0214120c6 100644 --- a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/BasicDetectPreviewFeatureAnalyzer.vb +++ b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/BasicDetectPreviewFeatureAnalyzer.vb @@ -2,6 +2,7 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Operations Imports Microsoft.NetCore.Analyzers.Runtime Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -16,6 +17,10 @@ Namespace Microsoft.NetCore.VisualBasic.Analyzers.Runtime Return identifier.ValueText.Equals(previewInterfaceSymbol.Name, StringComparison.OrdinalIgnoreCase) End Function + Protected Overrides Function SymbolFromAwaitOperation(operation As IAwaitOperation) As ISymbol + Return Nothing + End Function + Private Shared Function GetElementTypeForNullableAndArrayTypeNodes(parameterType As TypeSyntax) As TypeSyntax Dim ret As TypeSyntax = parameterType Dim loopVariable = TryCast(parameterType, NullableTypeSyntax) @@ -334,4 +339,4 @@ Namespace Microsoft.NetCore.VisualBasic.Analyzers.Runtime End Function End Class -End Namespace \ No newline at end of file +End Namespace diff --git a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Analyzer.CSharp.Utilities.projitems b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Analyzer.CSharp.Utilities.projitems index c6f9820f49f..cad6a604c50 100644 --- a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Analyzer.CSharp.Utilities.projitems +++ b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Analyzer.CSharp.Utilities.projitems @@ -10,6 +10,7 @@ + - \ No newline at end of file + diff --git a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Lightup/AwaitExpressionInfoWrapper.cs b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Lightup/AwaitExpressionInfoWrapper.cs new file mode 100644 index 00000000000..719a13858a8 --- /dev/null +++ b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Lightup/AwaitExpressionInfoWrapper.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace Analyzer.Utilities.Lightup +{ + internal static class AwaitExpressionInfoWrapper + { + private static Func? s_RuntimeAwaitMethodAccessor; + + extension(AwaitExpressionInfo info) + { + public IMethodSymbol? RuntimeAwaitMethod + { + get + { + LazyInitializer.EnsureInitialized(ref s_RuntimeAwaitMethodAccessor, () => + { + return LightupHelpers.CreatePropertyAccessor( + typeof(AwaitExpressionInfo), + "info", + "RuntimeAwaitMethod", + fallbackResult: null); + }); + + RoslynDebug.Assert(s_RuntimeAwaitMethodAccessor is not null); + return s_RuntimeAwaitMethodAccessor(info); + } + } + } + } +} diff --git a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler/Lightup/LightupHelpers.cs b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler/Lightup/LightupHelpers.cs index 39b63ec4ad0..8c714a20a37 100644 --- a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler/Lightup/LightupHelpers.cs +++ b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler/Lightup/LightupHelpers.cs @@ -53,7 +53,7 @@ internal static Func CreateSymbolPropertyAccessor CreatePropertyAccessor(type, "symbol", propertyName, fallbackResult); - private static Func CreatePropertyAccessor(Type? type, string parameterName, string propertyName, TProperty fallbackResult) + internal static Func CreatePropertyAccessor(Type? type, string parameterName, string propertyName, TProperty fallbackResult) { if (!TryGetProperty(type, propertyName, out var property)) { diff --git a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureUnitTests.Misc.cs b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureUnitTests.Misc.cs index a0fe473ba9a..b3b84fdf351 100644 --- a/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureUnitTests.Misc.cs +++ b/src/sdk/src/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureUnitTests.Misc.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Testing; using Xunit; using VerifyCS = Test.Utilities.CSharpCodeFixVerifier< @@ -95,7 +96,7 @@ private static VerifyCS.Test TestCSPreview(string csInput) [Fact] public async Task TestCatchPreviewException() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -131,7 +132,7 @@ static void Main(string[] args) [Fact] public async Task TestCustomMessageCustomURL() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -160,7 +161,7 @@ public class Lib [Fact] public async Task TestCustomMessageDefaultURL() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -187,7 +188,7 @@ public class Lib [Fact] public async Task TestDefaultMessageCustomURL() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -214,7 +215,7 @@ public class Lib [Fact] public async Task TestArrayOfPreviewTypes() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -243,7 +244,7 @@ public class Lib [Fact] public async Task TestArrayOfArraysOfPreviewTypes() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -270,7 +271,7 @@ public class Lib [Fact] public async Task TestPreviewLanguageFeaturesHeirarchy() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -304,7 +305,7 @@ public interface IProgram [Fact] public async Task TestPreviewLanguageFeatures() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -339,7 +340,7 @@ public interface IProgram [Fact] public async Task TestInterfaceMethodInvocation() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -401,7 +402,7 @@ public void Foo() [Fact] public async Task TestDelegate() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -426,7 +427,7 @@ static void Main(string[] args) [Fact] public async Task TestTypeOf() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -438,7 +439,7 @@ static void Main(string[] args) Console.WriteLine({|#0:typeof(IFoo)|}); } } - + [RequiresPreviewFeatures] interface IFoo { } }"; @@ -451,7 +452,7 @@ interface IFoo { } [Fact] public async Task TestSimpleCustomAttributeOnPreviewClass() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -485,7 +486,7 @@ class MyAttribute : Attribute [Fact] public async Task TestSimpleCustomAttribute() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -518,7 +519,7 @@ class MyAttribute : Attribute [Fact(Skip = "https://github.com/dotnet/roslyn-analyzers/issues/6134")] public async Task TestCustomAttribute() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -593,7 +594,7 @@ public MyAttribute(bool foo) {} [Fact] public async Task TestDeepNesting() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -638,7 +639,7 @@ public class NestedClass3 [Fact] public async Task TestNestedInvocation() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -666,7 +667,7 @@ class A [Fact] public async Task TestNestedClass() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -694,7 +695,7 @@ static void Main(string[] args) [Fact] public async Task TestCallback() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch {" + @@ -740,7 +741,7 @@ public class Foo [Fact] public async Task TestVbCaseInsensitiveCsharpSensitive() { - var csInput = @" + var csInput = @" using System.Runtime.Versioning; using System; namespace Preview_Feature_Scratch { @@ -775,7 +776,7 @@ public void UnmarkedMethodInUnMarkedInterface() { } test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewInterfaceRule).WithLocation(1).WithArguments("Program", "IProgram", DetectPreviewFeatureAnalyzer.DefaultURL)); await test.RunAsync(); - var vbInput = @" + var vbInput = @" Imports System Imports System.Runtime.Versioning Module Preview_Feature_Scratch @@ -802,5 +803,93 @@ End Module testVb.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewInterfaceRule).WithLocation(1).WithArguments("Program", "Iprogram", DetectPreviewFeatureAnalyzer.DefaultURL)); await testVb.RunAsync(); } + + [Fact] + public async Task VerifyRuntimeAsyncReportsDiagnostic() + { + var csInput = """ + using System.Threading.Tasks; + class C + { + async Task M() + { + await Task.CompletedTask; + } + } + """; + + var test = new RuntimeAsyncFixVerifier + { + TestState = + { + Sources = + { + csInput + } + }, + ExpectedDiagnostics = + { + // /0/Test0.cs(6,9): error CA2252: Using 'Await' requires opting into preview features. See https://aka.ms/dotnet-warnings/preview-features for more information. + VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.GeneralPreviewFeatureAttributeRule).WithSpan(6, 9, 6, 33).WithArguments("Await", DetectPreviewFeatureAnalyzer.DefaultURL) + } + }; + + await test.RunAsync(); + } + + [Fact] + public async Task VerifyRuntimeAsyncReportsDiagnostic_CustomAwaiter() + { + var csInput = """ + using System.Threading.Tasks; + class C + { + async Task M() + { + await Task.Yield(); + } + } + """; + + var test = new RuntimeAsyncFixVerifier + { + TestState = + { + Sources = + { + csInput + } + }, + ExpectedDiagnostics = + { + // /0/Test0.cs(6,9): error CA2252: Using 'UnsafeAwaitAwaiter' requires opting into preview features. See https://aka.ms/dotnet-warnings/preview-features for more information. + VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.GeneralPreviewFeatureAttributeRule).WithSpan(6, 9, 6, 27).WithArguments("UnsafeAwaitAwaiter", DetectPreviewFeatureAnalyzer.DefaultURL) + } + }; + await test.RunAsync(); + } + + private class RuntimeAsyncFixVerifier : VerifyCS.Test + { + public static readonly ReferenceAssemblies Net100 = new("net10.0", new PackageIdentity("Microsoft.NETCore.App.Ref", "10.0.0-rc.1.25451.107"), Path.Combine("ref", "net10.0")); + + public RuntimeAsyncFixVerifier() + { + ReferenceAssemblies = Net100; + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp10; + } + + protected override ParseOptions CreateParseOptions() + { + var options = base.CreateParseOptions(); + return options.WithFeatures([new("runtime-async", "on")]); + } + + protected override CompilationOptions CreateCompilationOptions() + { + var options = base.CreateCompilationOptions(); + return options.WithSpecificDiagnosticOptions([new("SYSLIB5007", ReportDiagnostic.Suppress)]); + } + } } } diff --git a/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj b/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj index de5612b1c47..20d248f368a 100644 --- a/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj +++ b/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj @@ -24,6 +24,7 @@ + diff --git a/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/SdkAnalyzerAssemblyRedirector.cs b/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/SdkAnalyzerAssemblyRedirector.cs index c81a829990c..23736deeb43 100644 --- a/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/SdkAnalyzerAssemblyRedirector.cs +++ b/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/SdkAnalyzerAssemblyRedirector.cs @@ -3,7 +3,10 @@ using System.Collections.Immutable; using System.ComponentModel.Composition; +using System.Text.Json; using Microsoft.CodeAnalysis.Workspaces.AnalyzerRedirecting; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; // Example: // FullPath: "C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.8\analyzers\dotnet\System.Windows.Forms.Analyzers.dll" @@ -13,9 +16,16 @@ namespace Microsoft.Net.Sdk.AnalyzerRedirecting; +/// +/// See documentation/general/analyzer-redirecting.md. +/// [Export(typeof(IAnalyzerAssemblyRedirector))] public sealed class SdkAnalyzerAssemblyRedirector : IAnalyzerAssemblyRedirector { + private readonly IVsActivityLog? _log; + + private readonly bool _enabled; + private readonly string? _insertedAnalyzersDirectory; /// @@ -24,62 +34,91 @@ public sealed class SdkAnalyzerAssemblyRedirector : IAnalyzerAssemblyRedirector private readonly ImmutableDictionary> _analyzerMap; [ImportingConstructor] - public SdkAnalyzerAssemblyRedirector() - : this(Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\DotNetRuntimeAnalyzers"))) { } + public SdkAnalyzerAssemblyRedirector(SVsServiceProvider serviceProvider) : this( + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"CommonExtensions\Microsoft\DotNet")), + serviceProvider.GetService()) + { + } // Internal for testing. - internal SdkAnalyzerAssemblyRedirector(string? insertedAnalyzersDirectory) + internal SdkAnalyzerAssemblyRedirector(string? insertedAnalyzersDirectory, IVsActivityLog? log = null) { + _log = log; + var enable = Environment.GetEnvironmentVariable("DOTNET_ANALYZER_REDIRECTING"); + _enabled = !"0".Equals(enable, StringComparison.OrdinalIgnoreCase) && !"false".Equals(enable, StringComparison.OrdinalIgnoreCase); _insertedAnalyzersDirectory = insertedAnalyzersDirectory; _analyzerMap = CreateAnalyzerMap(); } private ImmutableDictionary> CreateAnalyzerMap() { + if (!_enabled) + { + Log("Analyzer redirecting is disabled."); + return ImmutableDictionary>.Empty; + } + + var metadataFilePath = Path.Combine(_insertedAnalyzersDirectory, "metadata.json"); + if (!File.Exists(metadataFilePath)) + { + Log($"File does not exist: {metadataFilePath}"); + return ImmutableDictionary>.Empty; + } + + var versions = JsonSerializer.Deserialize>(File.ReadAllText(metadataFilePath)); + if (versions is null || versions.Count == 0) + { + Log($"Versions are empty: {metadataFilePath}"); + return ImmutableDictionary>.Empty; + } + var builder = ImmutableDictionary.CreateBuilder>(StringComparer.OrdinalIgnoreCase); // Expects layout like: - // VsInstallDir\SDK\RuntimeAnalyzers\WindowsDesktopAnalyzers\8.0.8\analyzers\dotnet\System.Windows.Forms.Analyzers.dll - // ~~~~~~~~~~~~~~~~~~~~~~~ = topLevelDirectory - // ~~~~~ = versionDirectory - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ = analyzerPath + // VsInstallDir\DotNetRuntimeAnalyzers\WindowsDesktopAnalyzers\analyzers\dotnet\System.Windows.Forms.Analyzers.dll + // ~~~~~~~~~~~~~~~~~~~~~~~ = topLevelDirectory + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ = analyzerPath foreach (string topLevelDirectory in Directory.EnumerateDirectories(_insertedAnalyzersDirectory)) { - foreach (string versionDirectory in Directory.EnumerateDirectories(topLevelDirectory)) + foreach (string analyzerPath in Directory.EnumerateFiles(topLevelDirectory, "*.dll", SearchOption.AllDirectories)) { - foreach (string analyzerPath in Directory.EnumerateFiles(versionDirectory, "*.dll", SearchOption.AllDirectories)) + if (!analyzerPath.StartsWith(topLevelDirectory, StringComparison.OrdinalIgnoreCase)) { - if (!analyzerPath.StartsWith(versionDirectory, StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - string version = Path.GetFileName(versionDirectory); - string analyzerName = Path.GetFileNameWithoutExtension(analyzerPath); - string pathSuffix = analyzerPath.Substring(versionDirectory.Length + 1 /* slash */); - pathSuffix = Path.GetDirectoryName(pathSuffix); - - AnalyzerInfo analyzer = new() { FullPath = analyzerPath, ProductVersion = version, PathSuffix = pathSuffix }; - - if (builder.TryGetValue(analyzerName, out var existing)) - { - existing.Add(analyzer); - } - else - { - builder.Add(analyzerName, [analyzer]); - } + continue; + } + + string subsetName = Path.GetFileName(topLevelDirectory); + if (!versions.TryGetValue(subsetName, out string version)) + { + continue; + } + + string analyzerName = Path.GetFileNameWithoutExtension(analyzerPath); + string pathSuffix = analyzerPath.Substring(topLevelDirectory.Length + 1 /* slash */); + pathSuffix = Path.GetDirectoryName(pathSuffix); + + AnalyzerInfo analyzer = new() { FullPath = analyzerPath, ProductVersion = version, PathSuffix = pathSuffix }; + + if (builder.TryGetValue(analyzerName, out var existing)) + { + existing.Add(analyzer); + } + else + { + builder.Add(analyzerName, [analyzer]); } } } + Log($"Loaded analyzer map ({builder.Count}): {_insertedAnalyzersDirectory}"); + return builder.ToImmutable(); } public string? RedirectPath(string fullPath) { - if (_analyzerMap.TryGetValue(Path.GetFileNameWithoutExtension(fullPath), out var analyzers)) + if (_enabled && _analyzerMap.TryGetValue(Path.GetFileNameWithoutExtension(fullPath), out var analyzers)) { foreach (AnalyzerInfo analyzer in analyzers) { @@ -134,4 +173,12 @@ static bool areVersionMajorMinorPartEqual(string version1, string version2) return 0 == string.Compare(version1, 0, version2, 0, secondDotIndex, StringComparison.OrdinalIgnoreCase); } } + + private void Log(string message) + { + _log?.LogEntry( + (uint)__ACTIVITYLOG_ENTRYTYPE.ALE_INFORMATION, + nameof(SdkAnalyzerAssemblyRedirector), + message); + } } diff --git a/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest b/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest index 3c3150875aa..cfa767fb3ca 100644 --- a/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest +++ b/src/sdk/src/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest @@ -13,10 +13,10 @@ - + - - + + amd64 diff --git a/src/sdk/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs b/src/sdk/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs index 6b891c586a2..ae38c8e2f61 100644 --- a/src/sdk/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs +++ b/src/sdk/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs @@ -32,7 +32,7 @@ public sealed class DotNetMSBuildSdkResolver : SdkResolver private readonly Func _getMsbuildRuntime; private readonly NETCoreSdkResolver _netCoreSdkResolver; - private const string DOTNET_HOST = nameof(DOTNET_HOST); + private const string DOTNET_HOST_PATH = nameof(DOTNET_HOST_PATH); private const string DotnetHostExperimentalKey = "DOTNET_EXPERIMENTAL_HOST_PATH"; private const string MSBuildTaskHostRuntimeVersion = "SdkResolverMSBuildTaskHostRuntimeVersion"; private const string SdkResolverHonoredGlobalJson = "SdkResolverHonoredGlobalJson"; @@ -245,12 +245,12 @@ private sealed class CachedState // this is the future-facing implementation. environmentVariablesToAdd ??= new Dictionary(1) { - [DOTNET_HOST] = fullPathToMuxer + [DOTNET_HOST_PATH] = fullPathToMuxer }; } else { - logger?.LogMessage($"Could not set '{DOTNET_HOST}' environment variable because dotnet executable '{fullPathToMuxer}' does not exist."); + logger?.LogMessage($"Could not set '{DOTNET_HOST_PATH}' environment variable because dotnet executable '{fullPathToMuxer}' does not exist."); } string? runtimeVersion = dotnetRoot != null ? diff --git a/src/sdk/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs b/src/sdk/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs index 678577e9053..a6d9f6d808a 100644 --- a/src/sdk/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs +++ b/src/sdk/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs @@ -28,7 +28,7 @@ static Interop() } // MSBuild SDK resolvers are required to be AnyCPU, but we have a native dependency and .NETFramework does not - // have a built-in facility for dynamically loading user native dlls for the appropriate platform. We therefore + // have a built-in facility for dynamically loading user native dlls for the appropriate platform. We therefore // preload the version with the correct architecture (from a corresponding sub-folder relative to us) on static // construction so that subsequent P/Invokes can find it. private static void PreloadWindowsLibrary(string dllFileName) @@ -124,6 +124,12 @@ internal static extern int hostfxr_get_dotnet_environment_info( hostfxr_get_dotnet_environment_info_result_fn result, IntPtr result_context); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void hostfxr_error_writer_fn(IntPtr message); + + [DllImport(Constants.HostFxr, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr hostfxr_set_error_writer(IntPtr error_writer); + public static class Windows { private const CharSet UTF16 = CharSet.Unicode; diff --git a/src/sdk/src/Resolvers/Microsoft.DotNet.NativeWrapper/NETCoreSdkResolverNativeWrapper.cs b/src/sdk/src/Resolvers/Microsoft.DotNet.NativeWrapper/NETCoreSdkResolverNativeWrapper.cs index 160346fbccf..b0571d439d0 100644 --- a/src/sdk/src/Resolvers/Microsoft.DotNet.NativeWrapper/NETCoreSdkResolverNativeWrapper.cs +++ b/src/sdk/src/Resolvers/Microsoft.DotNet.NativeWrapper/NETCoreSdkResolverNativeWrapper.cs @@ -23,6 +23,26 @@ public static SdkResolutionResult ResolveSdk( return result; } + public static string? GetGlobalJsonState(string globalJsonStartDirectory) + { + // We don't care about the actual SDK resolution, just the global.json information, + // so just pass empty string as executable directory for resolution. This means that + // we expect the call to fail to resolve an SDK. Set up the error writer to avoid + // output going to stderr. We reset it after the call. + var swallowErrors = new Interop.hostfxr_error_writer_fn(message => { }); + IntPtr errorWriter = Marshal.GetFunctionPointerForDelegate(swallowErrors); + IntPtr previousErrorWriter = Interop.hostfxr_set_error_writer(errorWriter); + try + { + SdkResolutionResult result = ResolveSdk(string.Empty, globalJsonStartDirectory); + return result.GlobalJsonState; + } + finally + { + Interop.hostfxr_set_error_writer(previousErrorWriter); + } + } + private sealed class SdkList { public string[]? Entries; diff --git a/src/sdk/src/StaticWebAssetsSdk/Tasks/Data/StaticWebAssetPathPattern.cs b/src/sdk/src/StaticWebAssetsSdk/Tasks/Data/StaticWebAssetPathPattern.cs index 23a0f96f660..5c9b48c486c 100644 --- a/src/sdk/src/StaticWebAssetsSdk/Tasks/Data/StaticWebAssetPathPattern.cs +++ b/src/sdk/src/StaticWebAssetsSdk/Tasks/Data/StaticWebAssetPathPattern.cs @@ -505,4 +505,71 @@ public override int GetHashCode() private static bool IsLiteralSegment(StaticWebAssetPathSegment segment) => segment.Parts.Count == 1 && segment.Parts[0].IsLiteral; internal static string PathWithoutTokens(string path) => Parse(path).ComputePatternLabel(); + + internal static string ExpandIdentityFileNameForFingerprint(string fileNamePattern, string fingerprint) + { + var pattern = Parse(fileNamePattern); + var sb = new StringBuilder(); + foreach (var segment in pattern.Segments) + { + var isLiteral = segment.Parts.Count == 1 && segment.Parts[0].IsLiteral; + if (isLiteral) + { + sb.Append(segment.Parts[0].Name); + continue; + } + + if (segment.IsOptional && !segment.IsPreferred) + { + continue; // skip non-preferred optional segments + } + + bool missingRequired = false; + foreach (var part in segment.Parts) + { + if (!part.IsLiteral && part.Value.IsEmpty) + { + var tokenName = part.Name.ToString(); + if (string.Equals(tokenName, "fingerprint", StringComparison.OrdinalIgnoreCase) && string.IsNullOrEmpty(fingerprint)) + { + missingRequired = true; + break; + } + } + } + if (missingRequired) + { + if (!segment.IsOptional) + { + throw new InvalidOperationException($"Token 'fingerprint' not provided for '{fileNamePattern}'."); + } + continue; + } + + foreach (var part in segment.Parts) + { + if (part.IsLiteral) + { + sb.Append(part.Name); + } + else if (!part.Value.IsEmpty) + { + sb.Append(part.Value); + } + else + { + var tokenName = part.Name.ToString(); + if (string.Equals(tokenName, "fingerprint", StringComparison.OrdinalIgnoreCase)) + { + sb.Append(fingerprint); + } + else + { + throw new InvalidOperationException($"Unsupported token '{tokenName}' in '{fileNamePattern}'."); + } + } + } + } + return sb.ToString(); + } } diff --git a/src/sdk/src/StaticWebAssetsSdk/Tasks/DefineStaticWebAssets.cs b/src/sdk/src/StaticWebAssetsSdk/Tasks/DefineStaticWebAssets.cs index 4d24ce9ed42..9f43c63845d 100644 --- a/src/sdk/src/StaticWebAssetsSdk/Tasks/DefineStaticWebAssets.cs +++ b/src/sdk/src/StaticWebAssetsSdk/Tasks/DefineStaticWebAssets.cs @@ -238,6 +238,14 @@ public override bool Execute() break; } + // IMPORTANT: Apply fingerprint pattern (which can change the file name) BEFORE computing identity + // for non-Discovered assets so that a synthesized identity incorporates the fingerprint pattern. + if (FingerprintCandidates) + { + matchContext.SetPathAndReinitialize(relativePathCandidate); + relativePathCandidate = StaticWebAsset.Normalize(fingerprintPatternMatcher.AppendFingerprintPattern(matchContext, identity)); + } + if (!string.Equals(SourceType, StaticWebAsset.SourceTypes.Discovered, StringComparison.OrdinalIgnoreCase)) { // We ignore the content root for publish only assets since it doesn't matter. @@ -246,16 +254,21 @@ public override bool Execute() if (computed) { + // If we synthesized identity and there is a fingerprint placeholder pattern in the file name + // expand it to the concrete fingerprinted file name while keeping RelativePath pattern form. + if (FingerprintCandidates && !string.IsNullOrEmpty(fingerprint)) + { + var fileNamePattern = Path.GetFileName(identity); + if (fileNamePattern.Contains("#[")) + { + var expanded = StaticWebAssetPathPattern.ExpandIdentityFileNameForFingerprint(fileNamePattern, fingerprint); + identity = Path.Combine(Path.GetDirectoryName(identity) ?? string.Empty, expanded); + } + } assetsCache.AppendCopyCandidate(hash, candidate.ItemSpec, identity); } } - if (FingerprintCandidates) - { - matchContext.SetPathAndReinitialize(relativePathCandidate); - relativePathCandidate = StaticWebAsset.Normalize(fingerprintPatternMatcher.AppendFingerprintPattern(matchContext, identity)); - } - var asset = StaticWebAsset.FromProperties( identity, sourceId, @@ -357,7 +370,13 @@ public override bool Execute() // Alternatively, we could be explicit here and support ContentRootSubPath to indicate where it needs to go. var identitySubPath = Path.GetDirectoryName(relativePath); var itemSpecFileName = Path.GetFileName(candidateFullPath); - var finalIdentity = Path.Combine(normalizedContentRoot, identitySubPath, itemSpecFileName); + var relativeFileName = Path.GetFileName(relativePath); + // If the relative path filename has been modified (e.g. fingerprint pattern appended) use it when synthesizing identity. + if (!string.IsNullOrEmpty(relativeFileName) && !string.Equals(relativeFileName, itemSpecFileName, StringComparison.OrdinalIgnoreCase)) + { + itemSpecFileName = relativeFileName; + } + var finalIdentity = Path.Combine(normalizedContentRoot, identitySubPath ?? string.Empty, itemSpecFileName); Log.LogMessage(MessageImportance.Low, "Identity for candidate '{0}' is '{1}' because it did not start with the content root '{2}'", candidate.ItemSpec, finalIdentity, normalizedContentRoot); return (finalIdentity, true); } @@ -493,7 +512,7 @@ private void UpdateAssetKindIfNecessary( { case (StaticWebAsset.AssetCopyOptions.Never, StaticWebAsset.AssetCopyOptions.Never): case (not StaticWebAsset.AssetCopyOptions.Never, not StaticWebAsset.AssetCopyOptions.Never): - var errorMessage = "Two assets found targeting the same path with incompatible asset kinds: " + Environment.NewLine + + var errorMessage = "Two assets found targeting the same path with incompatible asset kinds:" + Environment.NewLine + "'{0}' with kind '{1}'" + Environment.NewLine + "'{2}' with kind '{3}'" + Environment.NewLine + "for path '{4}'"; diff --git a/src/sdk/src/StaticWebAssetsSdk/Tasks/GenerateStaticWebAssetEndpointsManifest.cs b/src/sdk/src/StaticWebAssetsSdk/Tasks/GenerateStaticWebAssetEndpointsManifest.cs index 0387bb13105..f996a75b716 100644 --- a/src/sdk/src/StaticWebAssetsSdk/Tasks/GenerateStaticWebAssetEndpointsManifest.cs +++ b/src/sdk/src/StaticWebAssetsSdk/Tasks/GenerateStaticWebAssetEndpointsManifest.cs @@ -116,6 +116,8 @@ public override bool Execute() endpoint.AssetFile = asset.ResolvedAsset.ComputeTargetPath("", '/', StaticWebAssetTokenResolver.Instance); endpoint.Route = route; + EncodeLinkHeadersIfNeeded(endpoint); + Log.LogMessage(MessageImportance.Low, "Including endpoint '{0}' for asset '{1}' with final location '{2}'", endpoint.Route, endpoint.AssetFile, asset.TargetPath); } @@ -137,6 +139,48 @@ public override bool Execute() return !Log.HasLoggedErrors; } + private static void EncodeLinkHeadersIfNeeded(StaticWebAssetEndpoint endpoint) + { + for (var i = 0; i < endpoint.ResponseHeaders.Length; i++) + { + ref var header = ref endpoint.ResponseHeaders[i]; + if (!string.Equals(header.Name, "Link", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + var headerValues = header.Value.Split([','], StringSplitOptions.RemoveEmptyEntries); + for (var j = 0; j < headerValues.Length; j++) + { + ref var value = ref headerValues[j]; + value = EncodeHeaderValue(value); + } + header.Value = string.Join(",", headerValues); + } + } + + private static string EncodeHeaderValue(string header) + { + var index = header.IndexOf('<'); + if (index == -1) + { + return header; + } + index++; + var endIndex = header.IndexOf('>', index); + if (endIndex == -1) + { + return header; + } + var link = header.AsSpan(index, endIndex - index).ToString(); + var segments = link.Split('/'); + for (var j = 0; j < segments.Length; j++) + { + segments[j] = System.Net.WebUtility.UrlEncode(segments[j]); + } + var encoded = string.Join("/", segments); + return $"{header.Substring(0, index)}{encoded}{header.Substring(endIndex)}"; + } + private static (string, string[]) ParseAndSortPatterns(string patterns) { if (string.IsNullOrEmpty(patterns)) diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.cs.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.cs.xlf index 16913761477..d8efa3b3e0c 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.cs.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.cs.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: Vlastnosti {0} a {1} nelze zadat současně. Odeberte jednu nebo druhou. {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: Soubor {0} neexistuje. Ujistěte se prosím, že cesta ke grafu modulu runtime existuje. {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: Nelze najít odpovídající identifikátor RID pro {0} z [{1}] v grafu {2}. {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: Cílení na verzi Windows SDK s hodnotou 1, protože číslo revize bude odkazovat na CsWinRT 3.0, což je aktuálně ve verzi Preview. Aktuální projekt cílí na verzi Windows SDK {0}. Pokud to není záměrné, změňte číslo revize na 0, aby se místo toho používalo CsWinRT 2.x. {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.de.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.de.xlf index e2b12ac9dd3..81a06bb1271 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.de.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.de.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: Die Eigenschaften{0} und {1} können nicht beide angegeben werden. Entfernen Sie eine der beiden. {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: Die Datei „{0}“ existiert nicht. Stellen Sie sicher, dass der Pfad zum Runtimegraph vorhanden ist. {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: Es konnte keine passende RID für „{0}“ aus [{1}] im Graph „{2}“ gefunden werden. {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: Das Anvisieren einer Windows-SDK-Version mit der Revisionsnummer „1“ verweist auf CsWinRT 3.0, das sich derzeit in der Vorschau befindet. Das aktuelle Projekt verwendet die Windows-SDK-Version „{0}“. Wenn dies nicht beabsichtigt ist, ändern Sie die Revisionsnummer auf „0“, um stattdessen CsWinRT 2.x zu verwenden. {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.es.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.es.xlf index a60cb3887b8..c9928b5aa3e 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.es.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.es.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: no se pueden especificar las propiedades {0} y {1} a la vez. Quite uno u otra. {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: el archivo "{0}" no existe. Asegúrese de que la ruta de acceso del grafo en tiempo de ejecución existe. {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: no se puede encontrar un RID coincidente para "{0}" entre [{1}] en el grafo "{2}". {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: si se selecciona una versión del SDK de Windows con "1" como número de revisión, se hará referencia a CsWinRT 3.0, que está actualmente en versión preliminar. El proyecto actual tiene como destino la versión de Windows SDK "{0}". Si esto no está previsto, cambie el número de revisión a "0" para usar CsWinRT 2.x en su lugar. {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.fr.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.fr.xlf index b9277e0f067..4ff758501a7 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.fr.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.fr.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: les propriétés {0} et {1} ne peuvent pas être spécifiées simultanément. Supprimez l’une ou l’autre. {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: le fichier « {0} » n’existe pas. Veuillez vérifier que le chemin d’accès du graphique d’exécution existe. {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: nous ne pouvons pas trouver un RID correspondant à « {0} » parmi [{1}] dans le graphique « {2} ». {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: ciblez une version du Kit de développement logiciel Windows (Kit SDK Windows) avec « 1 » comme numéro de révision fait référence à CsWinRT 3.0 qui est actuellement en préversion. Le projet actuel cible la version du Kit de développement logiciel Windows (Kit SDK Windows) « {0} ». Si ce n’est pas votre intention, remplacez le numéro de révision par « 0 » pour utiliser CsWinRT 2.x à la place. {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.it.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.it.xlf index 9aaa04009f3..ab607e4f996 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.it.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.it.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: non è possibile specificare contemporaneamente le proprietà {0} e {1}. Rimuoverne una delle due. {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: il file '{0}' non esiste. Verificare che il percorso del grafo del runtime esista. {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: non è possibile trovare un RID corrispondente a '{0}' tra [{1}] nel grafo '{2}'. {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: l'impostazione di una versione di Windows SDK con '1' come numero di revisione come destinazione farà riferimento a CsWinRT 3.0, che è attualmente in anteprima. La destinazione del progetto corrente è impostata sulla versione di Windows SDK '{0}'. Se non è intenzionale, modificare il numero di revisione in '0' per usare invece CsWinRT 2.x. {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ja.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ja.xlf index 14b368defe2..b0201395826 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ja.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ja.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: {0} プロパティと {1} プロパティの両方を指定することはできません。どちらか一方を削除してください。 {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: ファイル '{0}' は存在しません。ランタイム グラフ パスが存在することを確認してください。 {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: グラフ '{2}' の [{1}] の中から'{0}' に一致する RID が見つかりません。 {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: リビジョン番号に '1' を指定して Windows SDK バージョンをターゲットにすると、現在プレビュー中の CsWinRT 3.0 が参照されます。現在のプロジェクトは Windows SDK バージョン '{0}' をターゲットにしています。これが意図されていない場合は、リビジョン番号を '0' に変更して CsWinRT 2.x を代わりに使用してください。 {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ko.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ko.xlf index aa63cc4a25c..20518f8a3d6 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ko.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ko.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: {0} 및 {1} 속성을 둘 다 지정할 수 없습니다. 둘 중 하나를 제거하세요. {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: '{0}' 파일이 없습니다. 런타임 그래프 경로가 있는지 확인하세요. {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: 그래프 '{2}'의 [{1}] 중에서 '{0}'에 대해 일치하는 RID를 찾을 수 없습니다. {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: 수정 번호가 '1'인 Windows SDK 버전을 대상으로 지정하면 현재 미리 보기 상태인 CsWinRT 3.0을 참조합니다. 현재 프로젝트가 Windows SDK 버전 '{0}'을(를) 대상으로 합니다. 의도하지 않은 경우 수정 번호를 '0'으로 변경하여 CsWinRT 2.x를 대신 사용합니다. {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.pl.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.pl.xlf index eedd5b42951..459bfc4b7af 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.pl.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.pl.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: nie można jednocześnie określić właściwości {0} i {1}. Usuń jedną lub drugą. {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: plik „{0}” nie istnieje. Upewnij się, że ścieżka grafu środowiska uruchomieniowego istnieje. {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: Nie można odnaleźć zgodnego identyfikatora RID dla elementu „{0}” spośród [{1}] na wykresie „{2}”. {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: określanie wersji zestawu Windows SDK z numerem poprawki „1” będzie odwoływać się do wersji CsWinRT 3.0, która jest obecnie dostępna w wersji zapoznawczej. Bieżący projekt jest przeznaczony dla zestawu Windows SDK w wersji „{0}”. Jeśli nie jest to zamierzone, zmień numer poprawki na „0”, aby zamiast tego użyć csWinRT 2.x. {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf index d0e2d6edf1e..cd0a8868c26 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: As propriedades {0} e {1} não podem ser especificadas ao mesmo tempo. Remova um ou outro. {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: O arquivo '{0}' não existe. Certifique-se de que o caminho do grafo de runtime exista. {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: Não foi possível encontrar um RID correspondente para '{0}' entre [{1}] no grafo '{2}'. {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: Apontar para uma versão do Windows SDK com '1' como número de revisão fará referência ao CsWinRT 3.0, que está atualmente em pré-visualização. O projeto atual está apontando para a versão '{0}' do Windows SDK. Se isso não for intencional, altere o número de revisão para '0' para usar o CsWinRT 2.x em vez disso. {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ru.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ru.xlf index d95fe548381..ca045eac8c2 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ru.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.ru.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: свойства {0} и {1} не могут быть указаны одновременно. Удалите одно из них. {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: файл "{0}" не существует. Убедитесь, что путь к графу среды выполнения существует. {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: не удалось найти соответствующий RID для "{0}" среди [{1}] в графе "{2}". {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: нацеливание на версию Windows SDK с номером редакции "1" будет ссылаться на CsWinRT 3.0, которая сейчас находится в предварительной версии. Текущий проект нацелен на Windows SDK версии "{0}". Если это не соответствует намерениям, измените номер редакции на "0", чтобы использовать CsWinRT 2.x. {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.tr.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.tr.xlf index ba5c00227db..92fde9043a2 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.tr.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.tr.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: {0} ve {1} özellikleri birlikte belirtilemez. Birini kaldırın. {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: '{0}' dosyası mevcut değil. Lütfen çalışma zamanı grafiği yolunun var olduğundan emin olun. {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: '{2}' grafiğindeki [{1}] arasından '{0}' için eşleşen bir RID bulunamadı. {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: Düzeltme numarası olarak '1' kullanılarak bir Windows SDK sürümünü hedeflemek, şu anda önizlemede olan CsWinRT 3.0’ı referans alacaktır. Geçerli proje Windows SDK sürüm '{0}' sürümünü hedefliyor. Eğer bu amaçlanmadıysa, CsWinRT 2.x kullanmak için düzeltme numarasını '0' olarak değiştirin. {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf index c546abfda52..6b177d50d08 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: 不能同时指定 {0} 和 {1} 属性。移除其中一个。 {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: 文件 "{0}" 不存在。请确保运行时图形路径存在。 {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: 无法在图 "{2}" 的 [{1}] 中找到与 "{0}" 匹配的 RID。 {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: 将修订号为 "1" 的 Windows SDK 版本作为目标时,将引用 CsWinRT 3.0,它目前为预览版。当前项目面向 Windows SDK 版本 "{0}"。如果这不是预期内的,请将修订号更改为 "0" 以改用 CsWinRT 2.x。 {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf index 1d857dbf118..31e3d5a6c83 100644 --- a/src/sdk/src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/sdk/src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf @@ -214,7 +214,7 @@ NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. - NETSDK1230: The {0} and {1} properties cannot both be specified. Remove one or the other. + NETSDK1230: {0} 和 {1} 屬性無法同時指定。請移除其中一者。 {StrBegins="NETSDK1230: "} @@ -863,7 +863,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. - NETSDK1231: File '{0}' does not exist. Please ensure the runtime graph path exists. + NETSDK1231: 檔案 '{0}' 不存在。請確認執行階段圖形路徑是否存在。 {StrBegins="NETSDK1231: "}{Locked="{0}"} @@ -965,7 +965,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. - NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'. + NETSDK1232: 無法在圖表 '{2}' 中的 '{1}' 項目中找到與 '{0}' 相符的 RID。 {StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"} @@ -1060,7 +1060,7 @@ The following are names of parameters or literal values and should not be transl NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. - NETSDK1229: Targeting a Windows SDK version with '1' as the revision number will reference CsWinRT 3.0, which is currently in preview. The current project is targeting the Windows SDK version '{0}'. If this is not intended, change the revision number to '0' to use CsWinRT 2.x instead. + NETSDK1229: 若將修訂編號設為「1」來指定 Windows SDK 版本,將參考目前處於預覽階段的 CsWinRT 3.0。目前專案的目標 Windows SDK 版本為 '{0}'。若非此意圖,請將修訂編號改為「0」以改用 CsWinRT 2.x。 {StrBegins="NETSDK1229: "} diff --git a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets index 6566bebb20e..0ac75dd8f8a 100644 --- a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets +++ b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets @@ -38,9 +38,14 @@ NOTE: This file is imported from the following contexts, so be aware when writin AssemblyFile="$(MicrosoftNETBuildTasksAssembly)" /> - + false + + false + - - - - - - - - - false + - - - - - - + + - + \ No newline at end of file diff --git a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-CSharp/xunit.runner.json b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-CSharp/xunit.runner.json deleted file mode 100644 index 86c7ea05b16..00000000000 --- a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-CSharp/xunit.runner.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json" -} diff --git a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/Company.TestProject1.fsproj b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/Company.TestProject1.fsproj index 3f4c2abd455..bf9c5b0b607 100644 --- a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/Company.TestProject1.fsproj +++ b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/Company.TestProject1.fsproj @@ -4,20 +4,8 @@ net10.0 TargetFrameworkOverride Company.TestProject1 - Exe true false - - - - - - - - - - - false @@ -25,13 +13,10 @@ + - - - - - - + + - + \ No newline at end of file diff --git a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/xunit.runner.json b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/xunit.runner.json deleted file mode 100644 index 86c7ea05b16..00000000000 --- a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/xunit.runner.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json" -} diff --git a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj index 10d29b50625..d88c072952f 100644 --- a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj +++ b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj @@ -4,30 +4,15 @@ Company.TestProject1 net10.0 TargetFrameworkOverride - Exe true false - - - - - - - - - - - false + - - - - - - + + - + \ No newline at end of file diff --git a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/xunit.runner.json b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/xunit.runner.json deleted file mode 100644 index 86c7ea05b16..00000000000 --- a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/xunit.runner.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json" -} diff --git a/src/sdk/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetCoreAppForTelemetry.cs b/src/sdk/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetCoreAppForTelemetry.cs index 54bc27a974d..2dfa4c6fda5 100644 --- a/src/sdk/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetCoreAppForTelemetry.cs +++ b/src/sdk/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetCoreAppForTelemetry.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Reflection; +using Microsoft.DotNet.Cli.Utils; namespace Microsoft.NET.Build.Tests { @@ -29,7 +30,7 @@ private string CreateTargetFrameworkEvalTelemetryJson( string publishProtocol = "null", string configuration = "Debug") { - return $"{{\"EventName\":\"targetframeworkeval\",\"Properties\":{{\"TargetFrameworkVersion\":\"{targetFrameworkVersion}\",\"RuntimeIdentifier\":\"{runtimeIdentifier}\",\"SelfContained\":\"{selfContained}\",\"UseApphost\":\"{useApphost}\",\"OutputType\":\"{outputType}\",\"UseArtifactsOutput\":\"{useArtifactsOutput}\",\"ArtifactsPathLocationType\":\"{artifactsPathLocationType}\",\"TargetPlatformIdentifier\":\"{targetPlatformIdentifier}\",\"UseMonoRuntime\":\"{useMonoRuntime}\",\"PublishAot\":\"{publishAot}\",\"PublishTrimmed\":\"{publishTrimmed}\",\"PublishSelfContained\":\"{publishSelfContained}\",\"PublishReadyToRun\":\"{publishReadyToRun}\",\"PublishReadyToRunComposite\":\"{publishReadyToRunComposite}\",\"PublishProtocol\":\"{publishProtocol}\",\"Configuration\":\"{configuration}\"}}"; + return $"{{\"EventName\":\"targetframeworkeval\",\"Properties\":{{\"TargetFrameworkVersion\":\"{targetFrameworkVersion}\",\"RuntimeIdentifier\":\"{runtimeIdentifier}\",\"SelfContained\":\"{selfContained}\",\"UseApphost\":\"{useApphost}\",\"OutputType\":\"{outputType}\",\"UseArtifactsOutput\":\"{useArtifactsOutput}\",\"ArtifactsPathLocationType\":\"{artifactsPathLocationType}\",\"TargetPlatformIdentifier\":\"{targetPlatformIdentifier}\",\"UseMonoRuntime\":\"{useMonoRuntime}\",\"PublishAot\":\"{publishAot}\",\"PublishTrimmed\":\"{publishTrimmed}\",\"PublishSelfContained\":\"{publishSelfContained}\",\"PublishReadyToRun\":\"{publishReadyToRun}\",\"PublishReadyToRunComposite\":\"{publishReadyToRunComposite}\",\"PublishProtocol\":\"{publishProtocol}\",\"Configuration\":\"{Sha256Hasher.HashWithNormalizedCasing(configuration)}\"}}"; } [CoreMSBuildOnlyFact] @@ -82,7 +83,7 @@ public void It_collects_multi_TargetFramework_version_and_other_properties() result .StdOut.Should() .Contain(CreateTargetFrameworkEvalTelemetryJson( - ".NETFramework,Version=v4.6", + ".NETFramework,Version=v4.6", targetPlatformIdentifier: "Windows", publishReadyToRunComposite: "null")) .And diff --git a/src/sdk/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs b/src/sdk/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs index ba14cd54eeb..2f473b12d72 100644 --- a/src/sdk/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs +++ b/src/sdk/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs @@ -6,6 +6,7 @@ using Basic.CompilerLog.Util; using Microsoft.Build.Logging.StructuredLogger; using Microsoft.CodeAnalysis; +using Microsoft.DotNet.Cli.Utils; namespace Microsoft.NET.Build.Tests; @@ -18,16 +19,16 @@ public sealed class RoslynBuildTaskTests(ITestOutputHelper log) : SdkTest(log) _ => throw new ArgumentOutOfRangeException(paramName: nameof(language)), }; - private static string CoreCompilerFileName(Language language) => CompilerFileNameWithoutExtension(language) + ".dll"; + private static string DotNetExecCompilerFileName(Language language) => CompilerFileNameWithoutExtension(language) + ".dll"; - private static string FxCompilerFileName(Language language) => CompilerFileNameWithoutExtension(language) + ".exe"; + private static string AppHostCompilerFileName(Language language) => CompilerFileNameWithoutExtension(language) + FileNameSuffixes.CurrentPlatform.Exe; [FullMSBuildOnlyTheory, CombinatorialData] public void FullMSBuild_SdkStyle(bool useSharedCompilation, Language language) { var testAsset = CreateProject(useSharedCompilation, language); var buildCommand = BuildAndRunUsingMSBuild(testAsset); - VerifyCompiler(buildCommand, CoreCompilerFileName(language), useSharedCompilation); + VerifyCompiler(buildCommand, AppHostCompilerFileName(language), useSharedCompilation); } [FullMSBuildOnlyTheory, CombinatorialData] @@ -38,7 +39,7 @@ public void FullMSBuild_SdkStyle_OptOut(bool useSharedCompilation, Language lang doc.Root!.Element("PropertyGroup")!.Add(new XElement("RoslynCompilerType", "Framework")); }); var buildCommand = BuildAndRunUsingMSBuild(testAsset); - VerifyCompiler(buildCommand, FxCompilerFileName(language), useSharedCompilation); + VerifyCompiler(buildCommand, AppHostCompilerFileName(language), useSharedCompilation); } [FullMSBuildOnlyTheory, CombinatorialData] @@ -50,7 +51,7 @@ public void FullMSBuild_NonSdkStyle(bool useSharedCompilation, Language language project.TargetFrameworkVersion = "v4.7.2"; }); var buildCommand = BuildAndRunUsingMSBuild(testAsset); - VerifyCompiler(buildCommand, FxCompilerFileName(language), useSharedCompilation); + VerifyCompiler(buildCommand, AppHostCompilerFileName(language), useSharedCompilation); } [FullMSBuildOnlyTheory, CombinatorialData] @@ -58,7 +59,7 @@ public void FullMSBuild_SdkStyle_ToolsetPackage(bool useSharedCompilation, Langu { var testAsset = CreateProject(useSharedCompilation, language, AddCompilersToolsetPackage); var buildCommand = BuildAndRunUsingMSBuild(testAsset); - VerifyCompiler(buildCommand, FxCompilerFileName(language), useSharedCompilation, toolsetPackage: true); + VerifyCompiler(buildCommand, AppHostCompilerFileName(language), useSharedCompilation, toolsetPackage: true); } [Theory, CombinatorialData] @@ -66,7 +67,7 @@ public void DotNet(bool useSharedCompilation, Language language) { var testAsset = CreateProject(useSharedCompilation, language); var buildCommand = BuildAndRunUsingDotNet(testAsset); - VerifyCompiler(buildCommand, CoreCompilerFileName(language), useSharedCompilation); + VerifyCompiler(buildCommand, AppHostCompilerFileName(language), useSharedCompilation); } // https://github.com/dotnet/sdk/issues/49665 @@ -75,7 +76,7 @@ public void DotNet_ToolsetPackage(bool useSharedCompilation, Language language) { var testAsset = CreateProject(useSharedCompilation, language, AddCompilersToolsetPackage); var buildCommand = BuildAndRunUsingDotNet(testAsset); - VerifyCompiler(buildCommand, CoreCompilerFileName(language), useSharedCompilation, toolsetPackage: true); + VerifyCompiler(buildCommand, DotNetExecCompilerFileName(language), useSharedCompilation, toolsetPackage: true); } private TestAsset CreateProject(bool useSharedCompilation, Language language, Action? configure = null, [CallerMemberName] string callingMethod = "") diff --git a/src/sdk/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs b/src/sdk/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs index a4cfbcb6d1f..20afab0e873 100644 --- a/src/sdk/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs +++ b/src/sdk/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs @@ -546,7 +546,8 @@ private void OverrideKnownILCompilerPackRuntimeIdentifiers(XDocument project, st project.Root.Add(new XElement(ns + "ItemGroup", new XElement(ns + "KnownILCompilerPack", new XAttribute("Update", "@(KnownILCompilerPack)"), - new XElement(ns + "ILCompilerRuntimeIdentifiers", runtimeIdentifiers)))); + new XElement(ns + "ILCompilerRuntimeIdentifiers", runtimeIdentifiers), + new XElement(ns + "ILCompilerPortableRuntimeIdentifiers", runtimeIdentifiers)))); } [RequiresMSBuildVersionTheory("17.0.0.32901")] diff --git a/src/sdk/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishIncrementally.cs b/src/sdk/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishIncrementally.cs index c47c6008969..9cd038e21ff 100644 --- a/src/sdk/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishIncrementally.cs +++ b/src/sdk/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishIncrementally.cs @@ -134,7 +134,7 @@ public void It_cleans_between_single_file_publishes() CheckPublishOutput(publishDir, expectedSingleExeFiles.Append(testProject.Name + ".dll"), null); } - [Fact] + [Fact(Skip = "https://github.com/dotnet/sdk/issues/50784")] public void It_cleans_before_trimmed_single_file_publish() { var testProject = new TestProject() diff --git a/src/sdk/test/Microsoft.NET.Sdk.BlazorWebAssembly.Tests/WasmPublishIntegrationTest.cs b/src/sdk/test/Microsoft.NET.Sdk.BlazorWebAssembly.Tests/WasmPublishIntegrationTest.cs index 6b26bd23794..cab0eb56e6e 100644 --- a/src/sdk/test/Microsoft.NET.Sdk.BlazorWebAssembly.Tests/WasmPublishIntegrationTest.cs +++ b/src/sdk/test/Microsoft.NET.Sdk.BlazorWebAssembly.Tests/WasmPublishIntegrationTest.cs @@ -1612,6 +1612,16 @@ public class TestReference fileInWwwroot.Should().Exist(); } + [RequiresMSBuildVersionTheory("17.12", Reason = "Needs System.Text.Json 8.0.5")] + [InlineData("")] + [InlineData("/p:BlazorFingerprintBlazorJs=false")] + public void Publish_BlazorWasmReferencedByAspNetCoreServer(string publishArg) + { + var testInstance = CreateAspNetSdkTestAsset("BlazorWasmReferencedByAspNetCoreServer"); + var publishCommand = CreatePublishCommand(testInstance, "Server"); + ExecuteCommand(publishCommand, publishArg).Should().Pass(); + } + private void VerifyTypeGranularTrimming(string blazorPublishDirectory) { VerifyAssemblyHasTypes(Path.Combine(blazorPublishDirectory, "_framework", "Microsoft.AspNetCore.Components.wasm"), new[] { diff --git a/src/sdk/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/ScopedCssIntegrationTests.cs b/src/sdk/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/ScopedCssIntegrationTests.cs index 9668d865691..6155a349898 100644 --- a/src/sdk/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/ScopedCssIntegrationTests.cs +++ b/src/sdk/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/ScopedCssIntegrationTests.cs @@ -3,6 +3,7 @@ #nullable disable +using System.Text.Json; using System.Text.RegularExpressions; using Microsoft.AspNetCore.StaticWebAssets.Tasks; @@ -617,5 +618,72 @@ public void RegeneratingScopedCss_ForProjectWithReferences() text.Should().Contain("background-color: orangered"); text.Should().MatchRegex(""".*@import '_content/ClassLibrary/ClassLibrary\.[a-zA-Z0-9]+\.bundle\.scp\.css.*"""); } + + [Fact] + public void Build_GeneratesUrlEncodedLinkHeaderForNonAsciiProjectName() + { + var testAsset = "RazorAppWithPackageAndP2PReference"; + ProjectDirectory = CreateAspNetSdkTestAsset(testAsset); + + // Rename the ClassLibrary project to have non-ASCII characters + var originalLibPath = Path.Combine(ProjectDirectory.Path, "AnotherClassLib"); + var newLibPath = Path.Combine(ProjectDirectory.Path, "项目"); + Directory.Move(originalLibPath, newLibPath); + + // Update the project file to set the assembly name and package ID + var libProjectFile = Path.Combine(newLibPath, "AnotherClassLib.csproj"); + var newLibProjectFile = Path.Combine(newLibPath, "项目.csproj"); + File.Move(libProjectFile, newLibProjectFile); + + // Add assembly name property to ensure consistent naming + var libProjectContent = File.ReadAllText(newLibProjectFile); + // Find the first PropertyGroup closing tag and replace it + var targetPattern = ""; + var replacement = " 项目\n 项目\n "; + var index = libProjectContent.IndexOf(targetPattern); + if (index >= 0) + { + libProjectContent = libProjectContent.Substring(0, index) + replacement + libProjectContent.Substring(index + targetPattern.Length); + } + File.WriteAllText(newLibProjectFile, libProjectContent); + + // Update the main project to reference the renamed library + var mainProjectFile = Path.Combine(ProjectDirectory.Path, "AppWithPackageAndP2PReference", "AppWithPackageAndP2PReference.csproj"); + var mainProjectContent = File.ReadAllText(mainProjectFile); + mainProjectContent = mainProjectContent.Replace(@"..\AnotherClassLib\AnotherClassLib.csproj", @"..\项目\项目.csproj"); + File.WriteAllText(mainProjectFile, mainProjectContent); + + // Ensure library has scoped CSS + var libCssFile = Path.Combine(newLibPath, "Views", "Shared", "Index.cshtml.css"); + if (!File.Exists(libCssFile)) + { + Directory.CreateDirectory(Path.GetDirectoryName(libCssFile)); + File.WriteAllText(libCssFile, ".test { color: red; }"); + } + + EnsureLocalPackagesExists(); + + var restore = CreateRestoreCommand(ProjectDirectory, "AppWithPackageAndP2PReference"); + ExecuteCommand(restore).Should().Pass(); + + var build = CreateBuildCommand(ProjectDirectory, "AppWithPackageAndP2PReference"); + ExecuteCommand(build).Should().Pass(); + + var intermediateOutputPath = build.GetIntermediateDirectory(DefaultTfm, "Debug").ToString(); + + // Check that the staticwebassets.build.endpoints.json file contains URL-encoded characters + var endpointsFile = Path.Combine(intermediateOutputPath, "staticwebassets.build.endpoints.json"); + new FileInfo(endpointsFile).Should().Exist(); + + var endpointsContent = File.ReadAllText(endpointsFile); + var json = JsonSerializer.Deserialize(endpointsContent, new JsonSerializerOptions(JsonSerializerDefaults.Web)); + + var styles = json.Endpoints.Where(e => e.Route.EndsWith("styles.css")); + + foreach (var styleEndpoint in styles) + { + styleEndpoint.ResponseHeaders.Should().Contain(h => h.Name.Equals("Link", StringComparison.OrdinalIgnoreCase) && h.Value.Contains("%E9%A1%B9%E7%9B%AE")); + } + } } } diff --git a/src/sdk/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/DiscoverStaticWebAssetsTest.cs b/src/sdk/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/DiscoverStaticWebAssetsTest.cs index 5fcd970d8c5..f252022d133 100644 --- a/src/sdk/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/DiscoverStaticWebAssetsTest.cs +++ b/src/sdk/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/DiscoverStaticWebAssetsTest.cs @@ -217,6 +217,69 @@ public void FingerprintsContentUsingPatternsWhenMoreThanOneExtension(string file asset.GetMetadata(nameof(StaticWebAsset.OriginalItemSpec)).Should().Be(Path.Combine("wwwroot", fileName)); } + [Fact] + [Trait("Category", "FingerprintIdentity")] + public void ComputesIdentity_UsingFingerprintPattern_ForComputedAssets_WhenIdentityNeedsComputation() + { + // Arrange: simulate a packaged asset (outside content root) with a RelativePath inside the app + var errorMessages = new List(); + var buildEngine = new Mock(); + buildEngine.Setup(e => e.LogErrorEvent(It.IsAny())) + .Callback(args => errorMessages.Add(args.Message)); + + // Create a physical file to allow fingerprint computation (tests override ResolveFileDetails returning null file otherwise) + var tempRoot = Path.Combine(Path.GetTempPath(), "swafp_identity_test"); + var nugetPackagePath = Path.Combine(tempRoot, "microsoft.aspnetcore.components.webassembly", "10.0.0-rc.1.25451.107", "build", "net10.0"); + Directory.CreateDirectory(nugetPackagePath); + var assetFileName = "blazor.webassembly.js"; + var assetFullPath = Path.Combine(nugetPackagePath, assetFileName); + File.WriteAllText(assetFullPath, "console.log('test');"); + // Relative path provided by the item (pre-fingerprinting) + var relativePath = Path.Combine("_framework", assetFileName).Replace('\\', '/'); + var contentRoot = Path.Combine("bin", "Release", "net10.0", "wwwroot"); + + var task = new DefineStaticWebAssets + { + BuildEngine = buildEngine.Object, + // Use default file resolution so the file we created is used for hashing. + TestResolveFileDetails = null, + CandidateAssets = + [ + new TaskItem(assetFullPath, new Dictionary + { + ["RelativePath"] = relativePath + }) + ], + // No RelativePathPattern, we trigger the branch that synthesizes identity under content root. + FingerprintPatterns = [ new TaskItem("Js", new Dictionary{{"Pattern","*.js"},{"Expression","#[.{fingerprint}]!"}})], + FingerprintCandidates = true, + SourceType = "Computed", + SourceId = "Client", + ContentRoot = contentRoot, + BasePath = "/", + AssetKind = StaticWebAsset.AssetKinds.All, + AssetTraitName = "WasmResource", + AssetTraitValue = "boot" + }; + + // Act + var result = task.Execute(); + + // Assert + result.Should().BeTrue($"Errors: {Environment.NewLine} {string.Join($"{Environment.NewLine} ", errorMessages)}"); + task.Assets.Length.Should().Be(1); + var asset = task.Assets[0]; + + // RelativePath should still contain the hard fingerprint pattern placeholder (not expanded yet) + asset.GetMetadata(nameof(StaticWebAsset.RelativePath)).Should().Be("_framework/blazor.webassembly#[.{fingerprint}]!.js"); + + // Identity must contain the ACTUAL fingerprint value in the file name (placeholder expanded) + var actualFingerprint = asset.GetMetadata(nameof(StaticWebAsset.Fingerprint)); + actualFingerprint.Should().NotBeNullOrEmpty(); + var expectedIdentity = Path.GetFullPath(Path.Combine(contentRoot, "_framework", $"blazor.webassembly.{actualFingerprint}.js")); + asset.ItemSpec.Should().Be(expectedIdentity); + } + [Fact] public void RespectsItemRelativePathWhenExplicitlySpecified() { @@ -450,7 +513,7 @@ public void FailsDiscoveringAssetsWhenThereIsAConflict( // Assert result.Should().Be(false); errorMessages.Count.Should().Be(1); - errorMessages[0].Should().Be($@"Two assets found targeting the same path with incompatible asset kinds: + errorMessages[0].Should().Be($@"Two assets found targeting the same path with incompatible asset kinds: '{Path.GetFullPath(Path.Combine("wwwroot", "candidate.js"))}' with kind '{firstKind}' '{Path.GetFullPath(Path.Combine("wwwroot", "candidate.publish.js"))}' with kind '{secondKind}' for path 'candidate.js'"); diff --git a/src/sdk/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/SdkAnalyzerAssemblyRedirectorTests.cs b/src/sdk/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/SdkAnalyzerAssemblyRedirectorTests.cs index 62a042d8f41..956161b134a 100644 --- a/src/sdk/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/SdkAnalyzerAssemblyRedirectorTests.cs +++ b/src/sdk/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/SdkAnalyzerAssemblyRedirectorTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; + namespace Microsoft.Net.Sdk.AnalyzerRedirecting.Tests; public class SdkAnalyzerAssemblyRedirectorTests(ITestOutputHelper log) : SdkTest(log) @@ -16,7 +18,8 @@ public void SameMajorMinorVersion(string a, string b) TestDirectory testDir = _testAssetsManager.CreateTestDirectory(identifier: "RuntimeAnalyzers"); var vsDir = Path.Combine(testDir.Path, "vs"); - var vsAnalyzerPath = FakeDll(vsDir, @$"AspNetCoreAnalyzers\{a}\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); + Metadata(vsDir, new() { { "AspNetCoreAnalyzers", a } }); + var vsAnalyzerPath = FakeDll(vsDir, @$"AspNetCoreAnalyzers\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); var sdkAnalyzerPath = FakeDll(testDir.Path, @$"sdk\packs\Microsoft.AspNetCore.App.Ref\{b}\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); var resolver = new SdkAnalyzerAssemblyRedirector(vsDir); @@ -30,7 +33,8 @@ public void DifferentPathSuffix() TestDirectory testDir = _testAssetsManager.CreateTestDirectory(identifier: "RuntimeAnalyzers"); var vsDir = Path.Combine(testDir.Path, "vs"); - FakeDll(vsDir, @"AspNetCoreAnalyzers\9.0.0-preview.5.24306.11\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); + Metadata(vsDir, new() { { "AspNetCoreAnalyzers", "9.0.0-preview.5.24306.11" } }); + FakeDll(vsDir, @"AspNetCoreAnalyzers\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); var sdkAnalyzerPath = FakeDll(testDir.Path, @"sdk\packs\Microsoft.AspNetCore.App.Ref\9.0.0-preview.7.24406.2\analyzers\dotnet\vb", "Microsoft.AspNetCore.App.Analyzers"); var resolver = new SdkAnalyzerAssemblyRedirector(vsDir); @@ -50,7 +54,8 @@ public void DifferentMajorMinorVersion(string a, string b) TestDirectory testDir = _testAssetsManager.CreateTestDirectory(identifier: "RuntimeAnalyzers"); var vsDir = Path.Combine(testDir.Path, "vs"); - FakeDll(vsDir, @$"AspNetCoreAnalyzers\{a}\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); + Metadata(vsDir, new() { { "AspNetCoreAnalyzers", a } }); + FakeDll(vsDir, @$"AspNetCoreAnalyzers\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); var sdkAnalyzerPath = FakeDll(testDir.Path, @$"sdk\packs\Microsoft.AspNetCore.App.Ref\{b}\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); var resolver = new SdkAnalyzerAssemblyRedirector(vsDir); @@ -65,4 +70,11 @@ private static string FakeDll(string root, string subdir, string name) File.WriteAllText(dllPath, ""); return dllPath; } + + private static void Metadata(string root, Dictionary versions) + { + var metadataFilePath = Path.Combine(root, "metadata.json"); + Directory.CreateDirectory(Path.GetDirectoryName(metadataFilePath)); + File.WriteAllText(metadataFilePath, JsonSerializer.Serialize(versions)); + } } diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/BlazorWasmReferencedByAspNetCoreServer.slnx b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/BlazorWasmReferencedByAspNetCoreServer.slnx new file mode 100644 index 00000000000..3e2628def73 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/BlazorWasmReferencedByAspNetCoreServer.slnx @@ -0,0 +1,4 @@ + + + + diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/App.razor b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/App.razor new file mode 100644 index 00000000000..f796217a715 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/App.razor @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/Client.csproj b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/Client.csproj new file mode 100644 index 00000000000..88afc4e9be5 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/Client.csproj @@ -0,0 +1,16 @@ + + + net10.0 + enable + enable + true + service-worker-assets.js + + + + + + + + + diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/Program.cs b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/Program.cs new file mode 100644 index 00000000000..121b10340b7 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/Program.cs @@ -0,0 +1,11 @@ +using Client; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; + +var builder = WebAssemblyHostBuilder.CreateDefault(args); +builder.RootComponents.Add("#app"); +builder.RootComponents.Add("head::after"); + +builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); + +await builder.Build().RunAsync(); diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/_Imports.razor b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/_Imports.razor new file mode 100644 index 00000000000..13999df0b5a --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/_Imports.razor @@ -0,0 +1,9 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.AspNetCore.Components.WebAssembly.Http +@using Microsoft.JSInterop +@using Client diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/css/app.css b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/css/app.css new file mode 100644 index 00000000000..a87511a380b --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/css/app.css @@ -0,0 +1,2 @@ +/* minimal css */ +body { font-family: sans-serif; } diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/index.html b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/index.html new file mode 100644 index 00000000000..f68fb3fc8ab --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/index.html @@ -0,0 +1,33 @@ + + + + + + Codestin Search App + + + + + + + + + + + + +
+ + + + +
+
+
+ An unhandled error has occurred. + Reload + 🗙 +
+ + + diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/manifest.webmanifest b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/manifest.webmanifest new file mode 100644 index 00000000000..85aa02b1454 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/manifest.webmanifest @@ -0,0 +1,8 @@ +{ + "name": "Client", + "short_name": "Client", + "start_url": "/", + "display": "standalone", + "background_color": "#ffffff", + "description": "Test Blazor WASM referenced by ASP.NET Core Server" +} diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/service-worker.js b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/service-worker.js new file mode 100644 index 00000000000..22fcb7e905a --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/service-worker.js @@ -0,0 +1,2 @@ +self.addEventListener('install', () => self.skipWaiting()); +self.addEventListener('activate', () => clients.claim()); diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/service-worker.published.js b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/service-worker.published.js new file mode 100644 index 00000000000..0074cb78762 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Client/wwwroot/service-worker.published.js @@ -0,0 +1,3 @@ +// Published service worker placeholder +self.addEventListener('install', () => self.skipWaiting()); +self.addEventListener('activate', () => clients.claim()); diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Server/Program.cs b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Server/Program.cs new file mode 100644 index 00000000000..068ce63ca79 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Server/Program.cs @@ -0,0 +1,16 @@ +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddOpenApi(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseWebAssemblyDebugging(); + app.MapOpenApi(); +} + +app.UseHttpsRedirection(); +app.MapStaticAssets(); +app.MapFallbackToFile("index.html"); +app.Run(); diff --git a/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Server/Server.csproj b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Server/Server.csproj new file mode 100644 index 00000000000..0dcd90d3c78 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/BlazorWasmReferencedByAspNetCoreServer/Server/Server.csproj @@ -0,0 +1,14 @@ + + + net10.0 + enable + enable + + + + + + + + + diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.ApiService/Program.cs b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.ApiService/Program.cs index 29ac848cd13..95a82316507 100644 --- a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.ApiService/Program.cs +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.ApiService/Program.cs @@ -37,7 +37,7 @@ app.Run(); -internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +internal record WeatherForecast(DateOnly Date, int TemperatureC, string Summary) { public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/Program.cs b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/Program.cs index 4e0bf9d4cee..7ef5c7a828e 100644 --- a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/Program.cs +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/Program.cs @@ -1,8 +1,13 @@ var builder = DistributedApplication.CreateBuilder(args); -var apiService = builder.AddProject("apiservice"); +var migration = builder.AddProject("migrationservice"); + +var apiService = builder + .AddProject("apiservice") + .WaitForCompletion(migration); builder.AddProject("webfrontend") + .WaitForCompletion(migration) .WithExternalHttpEndpoints() .WithReference(apiService) .WaitFor(apiService); diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/WatchAspire.AppHost.csproj b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/WatchAspire.AppHost.csproj index 90483a02df6..3f394f6f83c 100644 --- a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/WatchAspire.AppHost.csproj +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/WatchAspire.AppHost.csproj @@ -9,9 +9,10 @@ - - - + + + + diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Program.cs b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Program.cs new file mode 100644 index 00000000000..0abee487007 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Program.cs @@ -0,0 +1,10 @@ +using MigrationService; +using Microsoft.Extensions.Hosting; + +var builder = Host.CreateApplicationBuilder(args); + +builder.AddServiceDefaults(); +builder.Services.AddHostedService(); + +var host = builder.Build(); +host.Run(); diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Properties/launchSettings.json b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Properties/launchSettings.json new file mode 100644 index 00000000000..a312e8fb30b --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "MigrationService": { + "commandName": "Project", + "dotnetRunMessages": true, + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/WatchAspire.MigrationService.csproj b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/WatchAspire.MigrationService.csproj new file mode 100644 index 00000000000..621a330ee1b --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/WatchAspire.MigrationService.csproj @@ -0,0 +1,11 @@ + + + + net10.0 + enable + enable + + + + + \ No newline at end of file diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Worker.cs b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Worker.cs new file mode 100644 index 00000000000..4792261219d --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Worker.cs @@ -0,0 +1,22 @@ +using System.Diagnostics; + +namespace MigrationService; + +public class Worker(IHostApplicationLifetime hostApplicationLifetime, ILogger logger) : BackgroundService +{ + private static readonly ActivitySource s_activitySource = new("Migrations"); + + protected override Task ExecuteAsync(CancellationToken cancellationToken) + { + using var activity = s_activitySource.StartActivity( + "Migrating database", + ActivityKind.Client + ); + + logger.LogInformation("Migration complete"); + + hostApplicationLifetime.StopApplication(); + + return Task.CompletedTask; + } +} diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.Development.json b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.Development.json new file mode 100644 index 00000000000..cd7d0bc9100 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} \ No newline at end of file diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.json b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.json new file mode 100644 index 00000000000..0c208ae9181 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.Wasm/App.razor b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.Wasm/App.razor index 13f3043f0c4..eba23da9b5a 100644 --- a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.Wasm/App.razor +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.Wasm/App.razor @@ -1,4 +1,4 @@ - + diff --git a/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.slnx b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.slnx new file mode 100644 index 00000000000..d9a238e555d --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/WatchAspire/WatchAspire.slnx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/sdk/test/TestAssets/TestProjects/WatchHotReloadApp/Program.cs b/src/sdk/test/TestAssets/TestProjects/WatchHotReloadApp/Program.cs index f1d2a3b77bb..7171e0a1926 100644 --- a/src/sdk/test/TestAssets/TestProjects/WatchHotReloadApp/Program.cs +++ b/src/sdk/test/TestAssets/TestProjects/WatchHotReloadApp/Program.cs @@ -8,6 +8,7 @@ using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; +using System.Runtime.InteropServices; // diff --git a/src/sdk/test/TestAssets/TestProjects/WatchRazorWithDeps/RazorApp/Components/Pages/Home.razor b/src/sdk/test/TestAssets/TestProjects/WatchRazorWithDeps/RazorApp/Components/Pages/Home.razor index bb44fc2639e..2daa1cadc25 100644 --- a/src/sdk/test/TestAssets/TestProjects/WatchRazorWithDeps/RazorApp/Components/Pages/Home.razor +++ b/src/sdk/test/TestAssets/TestProjects/WatchRazorWithDeps/RazorApp/Components/Pages/Home.razor @@ -5,4 +5,11 @@ -Welcome to your new app. \ No newline at end of file +Welcome to your new app. + +@code{ + class C + { + /* member placeholder */ + } +} \ No newline at end of file diff --git a/src/sdk/test/dotnet-watch-test-browser/Program.cs b/src/sdk/test/dotnet-watch-test-browser/Program.cs new file mode 100644 index 00000000000..78f96cb73cc --- /dev/null +++ b/src/sdk/test/dotnet-watch-test-browser/Program.cs @@ -0,0 +1,146 @@ +using System; +using System.Buffers; +using System.Linq; +using System.Net.Http; +using System.Net.WebSockets; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +if (args is not [var urlArg]) +{ + Console.Error.WriteLine(); + return -1; +} + +Log($"Test browser opened at '{urlArg}'."); + +var url = new Uri(urlArg, UriKind.Absolute); + +var (webSocketUrls, publicKey) = await GetWebSocketUrlsAndPublicKey(url); + +var secret = RandomNumberGenerator.GetBytes(32); +var encryptedSecret = GetEncryptedSecret(publicKey, secret); + +using var webSocket = await OpenWebSocket(webSocketUrls, encryptedSecret); +var buffer = new byte[8 * 1024]; + +while (await TryReceiveMessageAsync(webSocket, message => Log($"Received: {Encoding.UTF8.GetString(message)}"))) +{ +} + +Log("WebSocket closed"); + +return 0; + +static async Task OpenWebSocket(string[] urls, string encryptedSecret) +{ + foreach (var url in urls) + { + try + { + var webSocket = new ClientWebSocket(); + webSocket.Options.AddSubProtocol(Uri.EscapeDataString(encryptedSecret)); + await webSocket.ConnectAsync(new Uri(url), CancellationToken.None); + return webSocket; + } + catch (Exception e) + { + Log($"Error connecting to '{url}': {e.Message}"); + } + } + + throw new InvalidOperationException("Unable to establish a connection."); +} + +static async ValueTask TryReceiveMessageAsync(WebSocket socket, Action> receiver) +{ + var writer = new ArrayBufferWriter(initialCapacity: 1024); + + while (true) + { + ValueWebSocketReceiveResult result; + var data = writer.GetMemory(); + try + { + result = await socket.ReceiveAsync(data, CancellationToken.None); + } + catch (Exception e) when (e is not OperationCanceledException) + { + Log($"Failed to receive response: {e.Message}"); + return false; + } + + if (result.MessageType == WebSocketMessageType.Close) + { + return false; + } + + writer.Advance(result.Count); + if (result.EndOfMessage) + { + break; + } + } + + receiver(writer.WrittenSpan); + return true; +} + +static async Task<(string[] url, string key)> GetWebSocketUrlsAndPublicKey(Uri baseUrl) +{ + var refreshScriptUrl = new Uri(baseUrl, "/_framework/aspnetcore-browser-refresh.js"); + + Log($"Fetching: {refreshScriptUrl}"); + + using var httpClient = new HttpClient(); + var content = await httpClient.GetStringAsync(refreshScriptUrl); + + Log($"Request for '{refreshScriptUrl}' succeeded"); + var webSocketUrl = GetWebSocketUrls(content); + var key = GetSharedSecretKey(content); + + Log($"WebSocket urls are '{string.Join(',', webSocketUrl)}'."); + Log($"Key is '{key}'."); + + return (webSocketUrl, key); +} + +static string[] GetWebSocketUrls(string refreshScript) +{ + var pattern = "const webSocketUrls = '([^']+)'"; + + var match = Regex.Match(refreshScript, pattern); + if (!match.Success) + { + throw new InvalidOperationException($"Can't find web socket URL pattern in the script: {pattern}{Environment.NewLine}{refreshScript}"); + } + + return match.Groups[1].Value.Split(","); +} + +static string GetSharedSecretKey(string refreshScript) +{ + var pattern = @"const sharedSecret = await getSecret\('([^']+)'\)"; + + var match = Regex.Match(refreshScript, pattern); + if (!match.Success) + { + throw new InvalidOperationException($"Can't find web socket shared secret pattern in the script: {pattern}{Environment.NewLine}{refreshScript}"); + } + + return match.Groups[1].Value; +} + +// Equivalent to getSecret function in WebSocketScriptInjection.js: +static string GetEncryptedSecret(string key, byte[] secret) +{ + using var rsa = RSA.Create(); + rsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(key), out _); + return Convert.ToBase64String(rsa.Encrypt(secret, RSAEncryptionPadding.OaepSHA256)); +} + +static void Log(string message) + => Console.WriteLine($"🧪 {message}"); diff --git a/src/sdk/test/dotnet-watch-test-browser/dotnet-watch-test-browser.csproj b/src/sdk/test/dotnet-watch-test-browser/dotnet-watch-test-browser.csproj new file mode 100644 index 00000000000..408cb9159c9 --- /dev/null +++ b/src/sdk/test/dotnet-watch-test-browser/dotnet-watch-test-browser.csproj @@ -0,0 +1,14 @@ + + + Exe + $(ToolsetTargetFramework) + MicrosoftAspNetCore + Microsoft.DotNet.Watch.UnitTests + + + + + + + + diff --git a/src/sdk/test/dotnet-watch.Tests/Browser/BrowserLaunchTests.cs b/src/sdk/test/dotnet-watch.Tests/Browser/BrowserLaunchTests.cs deleted file mode 100644 index f5fbf358d81..00000000000 --- a/src/sdk/test/dotnet-watch.Tests/Browser/BrowserLaunchTests.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.DotNet.Watch.UnitTests -{ - public class BrowserLaunchTests : DotNetWatchTestBase - { - private const string AppName = "WatchBrowserLaunchApp"; - - public BrowserLaunchTests(ITestOutputHelper logger) - : base(logger) - { - } - - [Fact] - public async Task LaunchesBrowserOnStart() - { - var testAsset = TestAssets.CopyTestAsset(AppName) - .WithSource(); - - App.Start(testAsset, [], testFlags: TestFlags.MockBrowser); - - // check that all app output is printed out: - await App.WaitForOutputLineContaining("Content root path:"); - - Assert.Contains(App.Process.Output, line => line.Contains("Application started. Press Ctrl+C to shut down.")); - Assert.Contains(App.Process.Output, line => line.Contains("Hosting environment: Development")); - - // Verify we launched the browser. - Assert.Contains(App.Process.Output, line => line.Contains("dotnet watch ⌚ Launching browser: https://localhost:5001")); - } - - [Fact] - public async Task UsesBrowserSpecifiedInEnvironment() - { - var testAsset = TestAssets.CopyTestAsset(AppName) - .WithSource(); - - App.EnvironmentVariables.Add("DOTNET_WATCH_BROWSER_PATH", "mycustombrowser.bat"); - - App.Start(testAsset, [], testFlags: TestFlags.MockBrowser); - await App.WaitForOutputLineContaining(MessageDescriptor.ConfiguredToUseBrowserRefresh); - await App.WaitForOutputLineContaining(MessageDescriptor.ConfiguredToLaunchBrowser); - - // Verify we launched the browser. - await App.AssertOutputLineStartsWith("dotnet watch ⌚ Launching browser: mycustombrowser.bat https://localhost:5001"); - } - } -} diff --git a/src/sdk/test/dotnet-watch.Tests/Browser/BrowserRefreshServerTests.cs b/src/sdk/test/dotnet-watch.Tests/Browser/BrowserRefreshServerTests.cs new file mode 100644 index 00000000000..236c99ec077 --- /dev/null +++ b/src/sdk/test/dotnet-watch.Tests/Browser/BrowserRefreshServerTests.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.DotNet.HotReload; +using Microsoft.Extensions.Logging; + +namespace Microsoft.DotNet.Watch.UnitTests; + +public class BrowserRefreshServerTests +{ + class TestListener : IDisposable + { + public void Dispose() + { + } + } + + [Theory] + [CombinatorialData] + public async Task ConfigureLaunchEnvironmentAsync(LogLevel logLevel, bool enableHotReload) + { + var middlewarePath = Path.GetTempPath(); + var middlewareFileName = Path.GetFileNameWithoutExtension(middlewarePath); + + var server = new TestBrowserRefreshServer(middlewarePath) + { + CreateAndStartHostImpl = () => new WebServerHost(new TestListener(), ["http://test.endpoint"], virtualDirectory: "/test/virt/dir") + }; + + ((TestLogger)server.Logger).IsEnabledImpl = level => level == logLevel; + + await server.StartAsync(CancellationToken.None); + + var envBuilder = new Dictionary(); + server.ConfigureLaunchEnvironment(envBuilder, enableHotReload); + + Assert.True(envBuilder.Remove("ASPNETCORE_AUTO_RELOAD_WS_KEY")); + + var expected = new List() + { + "ASPNETCORE_AUTO_RELOAD_VDIR=/test/virt/dir", + "ASPNETCORE_AUTO_RELOAD_WS_ENDPOINT=http://test.endpoint", + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES=" + middlewareFileName, + "DOTNET_STARTUP_HOOKS=" + middlewarePath, + }; + + if (enableHotReload) + { + expected.Add("DOTNET_MODIFIABLE_ASSEMBLIES=debug"); + } + + if (logLevel == LogLevel.Trace) + { + expected.Add("Logging__LogLevel__Microsoft.AspNetCore.Watch=Debug"); + } + + AssertEx.SequenceEqual(expected.Order(), envBuilder.OrderBy(e => e.Key).Select(e => $"{e.Key}={e.Value}")); + } +} diff --git a/src/sdk/test/dotnet-watch.Tests/Browser/BrowserTests.cs b/src/sdk/test/dotnet-watch.Tests/Browser/BrowserTests.cs new file mode 100644 index 00000000000..8fa4c00de4e --- /dev/null +++ b/src/sdk/test/dotnet-watch.Tests/Browser/BrowserTests.cs @@ -0,0 +1,110 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json; + +namespace Microsoft.DotNet.Watch.UnitTests; + +public class BrowserTests(ITestOutputHelper logger) : DotNetWatchTestBase(logger) +{ + [Fact] + public async Task LaunchesBrowserOnStart() + { + var testAsset = TestAssets.CopyTestAsset("WatchBrowserLaunchApp") + .WithSource(); + + App.Start(testAsset, [], testFlags: TestFlags.MockBrowser); + + // check that all app output is printed out: + await App.WaitForOutputLineContaining("Content root path:"); + + Assert.Contains(App.Process.Output, line => line.Contains("Application started. Press Ctrl+C to shut down.")); + Assert.Contains(App.Process.Output, line => line.Contains("Hosting environment: Development")); + + // Verify we launched the browser. + App.AssertOutputContains(MessageDescriptor.LaunchingBrowser.GetMessage("https://localhost:5001", "")); + } + + [PlatformSpecificFact(TestPlatforms.Windows)] // https://github.com/dotnet/aspnetcore/issues/63759 + public async Task BrowserDiagnostics() + { + var testAsset = TestAssets.CopyTestAsset("WatchRazorWithDeps") + .WithSource(); + + App.UseTestBrowser(); + + var url = $"http://localhost:{TestOptions.GetTestPort()}"; + var tfm = ToolsetInfo.CurrentTargetFramework; + + App.Start(testAsset, ["--urls", url], relativeProjectDirectory: "RazorApp", testFlags: TestFlags.ReadKeyFromStdin); + + await App.WaitForOutputLineContaining(MessageDescriptor.ConfiguredToUseBrowserRefresh); + await App.WaitForOutputLineContaining(MessageDescriptor.ConfiguredToLaunchBrowser); + await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); + + // Verify the browser has been launched. + await App.WaitUntilOutputContains($"🧪 Test browser opened at '{url}'."); + + // Verify the browser connected to the refresh server. + await App.WaitUntilOutputContains(MessageDescriptor.ConnectedToRefreshServer, "Browser #1"); + + App.Process.ClearOutput(); + + var homePagePath = Path.Combine(testAsset.Path, "RazorApp", "Components", "Pages", "Home.razor"); + + // rude edit: + UpdateSourceFile(homePagePath, src => src.Replace("/* member placeholder */", """ + public virtual int F() => 1; + """)); + + var errorMessage = $"{homePagePath}(13,9): error ENC0023: Adding an abstract method or overriding an inherited method requires restarting the application."; + var jsonErrorMessage = JsonSerializer.Serialize(errorMessage); + + await App.WaitForOutputLineContaining(errorMessage); + + await App.WaitForOutputLineContaining("Do you want to restart your app?"); + + await App.WaitUntilOutputContains($$""" + 🧪 Received: {"type":"HotReloadDiagnosticsv1","diagnostics":[{{jsonErrorMessage}}]} + """); + + // auto restart next time: + App.SendKey('a'); + + // browser page is reloaded when the app restarts: + await App.WaitForOutputLineContaining(MessageDescriptor.ReloadingBrowser, $"RazorApp ({tfm})"); + + // browser page was reloaded after the app restarted: + await App.WaitUntilOutputContains(""" + 🧪 Received: Reload + """); + + await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); + + // another rude edit: + UpdateSourceFile(homePagePath, src => src.Replace("public virtual int F() => 1;", "/* member placeholder */")); + + errorMessage = $"{homePagePath}(11,5): error ENC0033: Deleting method 'F()' requires restarting the application."; + await App.WaitForOutputLineContaining("[auto-restart] " + errorMessage); + + await App.WaitUntilOutputContains($$""" + 🧪 Received: {"type":"HotReloadDiagnosticsv1","diagnostics":["Restarting application to apply changes ..."]} + """); + + await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); + + // browser page was reloaded after the app restarted: + await App.WaitUntilOutputContains(""" + 🧪 Received: Reload + """); + + // valid edit: + UpdateSourceFile(homePagePath, src => src.Replace("/* member placeholder */", "public int F() => 1;")); + + await App.WaitForOutputLineContaining(MessageDescriptor.HotReloadSucceeded); + + await App.WaitUntilOutputContains($$""" + 🧪 Received: {"type":"AspNetCoreHotReloadApplied"} + """); + } +} diff --git a/src/sdk/test/dotnet-watch.Tests/Build/EvaluationTests.cs b/src/sdk/test/dotnet-watch.Tests/Build/EvaluationTests.cs index 5a678687533..4c1bcbdbb30 100644 --- a/src/sdk/test/dotnet-watch.Tests/Build/EvaluationTests.cs +++ b/src/sdk/test/dotnet-watch.Tests/Build/EvaluationTests.cs @@ -236,8 +236,13 @@ public async Task ProjectReferences_OneLevel() var project1 = new TestProject("Project1") { + IsExe = true, TargetFrameworks = $"{ToolsetInfo.CurrentTargetFramework};net462", ReferencedProjects = { project2 }, + SourceFiles = + { + { "Project1.cs", s_emptyProgram }, + }, }; var testAsset = _testAssets.CreateTestProject(project1); @@ -271,8 +276,13 @@ public async Task TransitiveProjectReferences_TwoLevels() var project1 = new TestProject("Project1") { + IsExe = true, TargetFrameworks = $"{ToolsetInfo.CurrentTargetFramework};net462", ReferencedProjects = { project2 }, + SourceFiles = + { + { "Project1.cs", s_emptyProgram }, + }, }; var testAsset = _testAssets.CreateTestProject(project1); @@ -305,8 +315,13 @@ public async Task SingleTargetRoot_MultiTargetedDependency(bool specifyTargetFra var project1 = new TestProject("Project1") { + IsExe = true, TargetFrameworks = ToolsetInfo.CurrentTargetFramework, ReferencedProjects = { project2 }, + SourceFiles = + { + { "Project1.cs", s_emptyProgram }, + }, }; var testAsset = _testAssets.CreateTestProject(project1, identifier: specifyTargetFramework.ToString()); @@ -479,8 +494,13 @@ public async Task MsbuildOutput() var project1 = new TestProject("Project1") { + IsExe = true, TargetFrameworks = "net462", ReferencedProjects = { project2 }, + SourceFiles = + { + { "Program.cs", s_emptyProgram }, + }, }; var testAsset = _testAssets.CreateTestProject(project1); @@ -495,9 +515,9 @@ public async Task MsbuildOutput() Assert.Null(result); // note: msbuild prints errors to stdout, we match the pattern and report as error: - AssertEx.Equal( + Assert.Contains( $"[Error] {project1Path} : error NU1201: Project Project2 is not compatible with net462 (.NETFramework,Version=v4.6.2). Project Project2 supports: netstandard2.1 (.NETStandard,Version=v2.1)", - _logger.GetAndClearMessages().Single(m => m.Contains("error NU1201"))); + _logger.GetAndClearMessages()); } private readonly struct ExpectedFile(string path, string? staticAssetUrl = null, bool targetsOnly = false, bool graphOnly = false) diff --git a/src/sdk/test/dotnet-watch.Tests/CommandLine/LaunchSettingsTests.cs b/src/sdk/test/dotnet-watch.Tests/CommandLine/LaunchSettingsTests.cs index 24ee2076885..95bbd1d7965 100644 --- a/src/sdk/test/dotnet-watch.Tests/CommandLine/LaunchSettingsTests.cs +++ b/src/sdk/test/dotnet-watch.Tests/CommandLine/LaunchSettingsTests.cs @@ -92,22 +92,15 @@ public async Task RunsWithIterationEnvVariable() App.Start(testAsset, []); - await App.AssertStarted(); + await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForFileChangeBeforeRestarting); - var source = Path.Combine(testAsset.Path, "Program.cs"); - var contents = File.ReadAllText(source); - const string messagePrefix = "DOTNET_WATCH_ITERATION = "; + App.AssertOutputContains("DOTNET_WATCH_ITERATION = 1"); + App.Process.ClearOutput(); - var value = await App.AssertOutputLineStartsWith(messagePrefix); - Assert.Equal(1, int.Parse(value, CultureInfo.InvariantCulture)); + UpdateSourceFile(Path.Combine(testAsset.Path, "Program.cs")); await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForFileChangeBeforeRestarting); - - UpdateSourceFile(source); - await App.AssertStarted(); - - value = await App.AssertOutputLineStartsWith(messagePrefix); - Assert.Equal(2, int.Parse(value, CultureInfo.InvariantCulture)); + App.AssertOutputContains("DOTNET_WATCH_ITERATION = 2"); } [Fact] diff --git a/src/sdk/test/dotnet-watch.Tests/ConsoleReporterTests.cs b/src/sdk/test/dotnet-watch.Tests/ConsoleReporterTests.cs index 7fb1c564451..8df1601dc0d 100644 --- a/src/sdk/test/dotnet-watch.Tests/ConsoleReporterTests.cs +++ b/src/sdk/test/dotnet-watch.Tests/ConsoleReporterTests.cs @@ -18,19 +18,19 @@ public void WritesToStandardStreams(bool suppressEmojis) var reporter = new ConsoleReporter(testConsole, verbose: true, quiet: false, suppressEmojis: suppressEmojis); reporter.Report(id: default, Emoji.Watch, MessageSeverity.Verbose, "verbose {0}"); - Assert.Equal($"dotnet watch {(suppressEmojis ? ":" : "⌚")} verbose {{0}}" + EOL, testConsole.GetOutput()); + Assert.Equal($"dotnet watch {(suppressEmojis ? ":" : "⌚")} verbose {{0}}" + EOL, testConsole.GetError()); testConsole.Clear(); reporter.Report(id: default, Emoji.Watch, MessageSeverity.Output, "out"); - Assert.Equal($"dotnet watch {(suppressEmojis ? ":" : "⌚")} out" + EOL, testConsole.GetOutput()); + Assert.Equal($"dotnet watch {(suppressEmojis ? ":" : "⌚")} out" + EOL, testConsole.GetError()); testConsole.Clear(); reporter.Report(id: default, Emoji.Warning, MessageSeverity.Warning, "warn"); - Assert.Equal($"dotnet watch {(suppressEmojis ? ":" : "⚠")} warn" + EOL, testConsole.GetOutput()); + Assert.Equal($"dotnet watch {(suppressEmojis ? ":" : "⚠")} warn" + EOL, testConsole.GetError()); testConsole.Clear(); reporter.Report(id: default, Emoji.Error, MessageSeverity.Error, "error"); - Assert.Equal($"dotnet watch {(suppressEmojis ? ":" : "❌")} error" + EOL, testConsole.GetOutput()); + Assert.Equal($"dotnet watch {(suppressEmojis ? ":" : "❌")} error" + EOL, testConsole.GetError()); testConsole.Clear(); } diff --git a/src/sdk/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/src/sdk/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index a7a1bcda192..104438d0808 100644 --- a/src/sdk/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/src/sdk/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -429,7 +429,7 @@ public async Task AutoRestartOnRudeEdit(bool nonInteractive) await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); App.AssertOutputContains(MessageDescriptor.RestartNeededToApplyChanges); - App.AssertOutputContains($"⌚ [auto-restart] {programPath}(38,11): error ENC0023: Adding an abstract method or overriding an inherited method requires restarting the application."); + App.AssertOutputContains($"⌚ [auto-restart] {programPath}(39,11): error ENC0023: Adding an abstract method or overriding an inherited method requires restarting the application."); App.AssertOutputContains($"[WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Exited"); App.AssertOutputContains($"[WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Launched"); App.Process.ClearOutput(); @@ -459,7 +459,7 @@ public async Task AutoRestartOnRudeEditAfterRestartPrompt() await App.AssertOutputLineStartsWith(" ❔ Do you want to restart your app? Yes (y) / No (n) / Always (a) / Never (v)", failure: _ => false); App.AssertOutputContains(MessageDescriptor.RestartNeededToApplyChanges); - App.AssertOutputContains($"❌ {programPath}(38,11): error ENC0023: Adding an abstract method or overriding an inherited method requires restarting the application."); + App.AssertOutputContains($"❌ {programPath}(39,11): error ENC0023: Adding an abstract method or overriding an inherited method requires restarting the application."); App.Process.ClearOutput(); App.SendKey('a'); @@ -476,7 +476,7 @@ public async Task AutoRestartOnRudeEditAfterRestartPrompt() await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); App.AssertOutputContains(MessageDescriptor.RestartNeededToApplyChanges); - App.AssertOutputContains($"⌚ [auto-restart] {programPath}(38,1): error ENC0033: Deleting method 'F()' requires restarting the application."); + App.AssertOutputContains($"⌚ [auto-restart] {programPath}(39,1): error ENC0033: Deleting method 'F()' requires restarting the application."); App.AssertOutputContains($"[WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Exited"); App.AssertOutputContains($"[WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Launched"); } @@ -514,7 +514,7 @@ public async Task AutoRestartOnNoEffectEdit(bool nonInteractive) await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); App.AssertOutputContains(MessageDescriptor.RestartNeededToApplyChanges); - App.AssertOutputContains($"⌚ [auto-restart] {programPath}(16,19): warning ENC0118: Changing 'top-level code' might not have any effect until the application is restarted."); + App.AssertOutputContains($"⌚ [auto-restart] {programPath}(17,19): warning ENC0118: Changing 'top-level code' might not have any effect until the application is restarted."); App.AssertOutputContains($"[WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Exited"); App.AssertOutputContains($"[WatchHotReloadApp ({ToolsetInfo.CurrentTargetFramework})] Launched"); App.AssertOutputContains(""); @@ -721,6 +721,8 @@ class AppUpdateHandler [PlatformSpecificFact(TestPlatforms.Windows)] public async Task GracefulTermination_Windows() { + var tfm = ToolsetInfo.CurrentTargetFramework; + var testAsset = TestAssets.CopyTestAsset("WatchHotReloadApp") .WithSource(); @@ -739,7 +741,7 @@ public async Task GracefulTermination_Windows() await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); - await App.WaitUntilOutputContains(new Regex(@"dotnet watch 🕵️ \[.*\] Windows Ctrl\+C handling enabled.")); + await App.WaitUntilOutputContains($"dotnet watch 🕵️ [WatchHotReloadApp ({tfm})] Windows Ctrl+C handling enabled."); await App.WaitUntilOutputContains("Started"); @@ -749,7 +751,38 @@ public async Task GracefulTermination_Windows() await App.WaitUntilOutputContains("exited with exit code 0."); } - [PlatformSpecificTheory(TestPlatforms.Windows, Skip = "https://github.com/dotnet/sdk/issues/49928")] // https://github.com/dotnet/sdk/issues/49307 + [PlatformSpecificFact(TestPlatforms.AnyUnix)] + public async Task GracefulTermination_Unix() + { + var tfm = ToolsetInfo.CurrentTargetFramework; + + var testAsset = TestAssets.CopyTestAsset("WatchHotReloadApp") + .WithSource(); + + var programPath = Path.Combine(testAsset.Path, "Program.cs"); + + UpdateSourceFile(programPath, src => src.Replace("// ", """ + using var termSignalRegistration = PosixSignalRegistration.Create(PosixSignal.SIGTERM, _ => + { + Console.WriteLine("SIGTERM detected! Performing cleanup..."); + }); + """)); + + App.Start(testAsset, [], testFlags: TestFlags.ReadKeyFromStdin); + + await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); + + await App.WaitUntilOutputContains($"dotnet watch 🕵️ [WatchHotReloadApp ({tfm})] Posix signal handlers registered."); + + await App.WaitUntilOutputContains("Started"); + + App.SendControlC(); + + await App.WaitForOutputLineContaining("SIGTERM detected! Performing cleanup..."); + await App.WaitUntilOutputContains("exited with exit code 0."); + } + + [PlatformSpecificTheory(TestPlatforms.Windows, Skip = "https://github.com/dotnet/sdk/issues/49928")] // https://github.com/dotnet/aspnetcore/issues/63759 [CombinatorialData] public async Task BlazorWasm(bool projectSpecifiesCapabilities) { @@ -777,7 +810,7 @@ public async Task BlazorWasm(bool projectSpecifiesCapabilities) App.AssertOutputContains(MessageDescriptor.ConfiguredToLaunchBrowser); // Browser is launched based on blazor-devserver output "Now listening on: ...". - await App.WaitUntilOutputContains($"dotnet watch ⌚ Launching browser: http://localhost:{port}"); + await App.WaitUntilOutputContains(MessageDescriptor.LaunchingBrowser.GetMessage($"http://localhost:{port}", "")); // Middleware should have been loaded to blazor-devserver before the browser is launched: App.AssertOutputContains("dbug: Microsoft.AspNetCore.Watch.BrowserRefresh.BlazorWasmHotReloadMiddleware[0]"); @@ -809,7 +842,7 @@ public async Task BlazorWasm(bool projectSpecifiesCapabilities) } } - [PlatformSpecificFact(TestPlatforms.Windows)] // "https://github.com/dotnet/sdk/issues/49307") + [PlatformSpecificFact(TestPlatforms.Windows)] // https://github.com/dotnet/aspnetcore/issues/63759 public async Task BlazorWasm_MSBuildWarning() { var testAsset = TestAssets @@ -831,7 +864,7 @@ public async Task BlazorWasm_MSBuildWarning() await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); } - [PlatformSpecificFact(TestPlatforms.Windows)] // "https://github.com/dotnet/sdk/issues/49307") + [PlatformSpecificFact(TestPlatforms.Windows)] // https://github.com/dotnet/aspnetcore/issues/63759 public async Task BlazorWasm_Restart() { var testAsset = TestAssets.CopyTestAsset("WatchBlazorWasm") @@ -847,14 +880,14 @@ public async Task BlazorWasm_Restart() App.AssertOutputContains(MessageDescriptor.PressCtrlRToRestart); // Browser is launched based on blazor-devserver output "Now listening on: ...". - await App.WaitUntilOutputContains($"dotnet watch ⌚ Launching browser: http://localhost:{port}"); + await App.WaitUntilOutputContains(MessageDescriptor.LaunchingBrowser.GetMessage($"http://localhost:{port}", "")); App.SendControlR(); await App.WaitUntilOutputContains(MessageDescriptor.ReloadingBrowser); } - [PlatformSpecificFact(TestPlatforms.Windows, Skip = "https://github.com/dotnet/sdk/issues/49928")] // "https://github.com/dotnet/sdk/issues/49307") + [PlatformSpecificFact(TestPlatforms.Windows, Skip = "https://github.com/dotnet/sdk/issues/49928")] // https://github.com/dotnet/aspnetcore/issues/63759 public async Task BlazorWasmHosted() { var testAsset = TestAssets.CopyTestAsset("WatchBlazorWasmHosted") @@ -878,7 +911,7 @@ public async Task BlazorWasmHosted() App.AssertOutputContains($"dotnet watch ⌚ [blazorhosted ({tfm})] Capabilities: 'Baseline AddMethodToExistingType AddStaticFieldToExistingType AddInstanceFieldToExistingType NewTypeDefinition ChangeCustomAttributes UpdateParameters GenericUpdateMethod GenericAddMethodToExistingType GenericAddFieldToExistingType AddFieldRva'"); } - [PlatformSpecificFact(TestPlatforms.Windows)] // "https://github.com/dotnet/sdk/issues/49307") + [PlatformSpecificFact(TestPlatforms.Windows)] // https://github.com/dotnet/aspnetcore/issues/63759 public async Task Razor_Component_ScopedCssAndStaticAssets() { var testAsset = TestAssets.CopyTestAsset("WatchRazorWithDeps") @@ -891,7 +924,7 @@ public async Task Razor_Component_ScopedCssAndStaticAssets() App.AssertOutputContains(MessageDescriptor.ConfiguredToUseBrowserRefresh); App.AssertOutputContains(MessageDescriptor.ConfiguredToLaunchBrowser); - App.AssertOutputContains($"dotnet watch ⌚ Launching browser: http://localhost:{port}"); + App.AssertOutputContains(MessageDescriptor.LaunchingBrowser.GetMessage($"http://localhost:{port}", "")); App.Process.ClearOutput(); var scopedCssPath = Path.Combine(testAsset.Path, "RazorClassLibrary", "Components", "Example.razor.css"); @@ -1114,7 +1147,7 @@ public static void PrintDirectoryName([CallerFilePathAttribute] string filePath await App.AssertOutputLineStartsWith("> NewSubdir", failure: _ => false); } - [PlatformSpecificFact(TestPlatforms.Windows)] // "https://github.com/dotnet/sdk/issues/49307") + [PlatformSpecificFact(TestPlatforms.Windows)] // https://github.com/dotnet/aspnetcore/issues/63759 public async Task Aspire_BuildError_ManualRestart() { var tfm = ToolsetInfo.CurrentTargetFramework; @@ -1135,8 +1168,13 @@ public async Task Aspire_BuildError_ManualRestart() // check that Aspire server output is logged via dotnet-watch reporter: await App.WaitUntilOutputContains("dotnet watch ⭐ Now listening on:"); - // wait until after DCP session started: - await App.WaitUntilOutputContains("dotnet watch ⭐ Session started: #1"); + // wait until after all DCP sessions have started: + await App.WaitUntilOutputContains("dotnet watch ⭐ Session started: #3"); + App.AssertOutputContains("dotnet watch ⭐ Session started: #1"); + App.AssertOutputContains("dotnet watch ⭐ Session started: #2"); + + // MigrationService terminated: + App.AssertOutputContains("dotnet watch ⭐ [#1] Sending 'sessionTerminated'"); // working directory of the service should be it's project directory: await App.WaitUntilOutputContains($"ApiService working directory: '{Path.GetDirectoryName(serviceProjectPath)}'"); @@ -1176,9 +1214,7 @@ public async Task Aspire_BuildError_ManualRestart() App.AssertOutputContains("Application is shutting down..."); - // We don't have means to gracefully terminate process on Windows, see https://github.com/dotnet/runtime/issues/109432 App.AssertOutputContains($"[WatchAspire.ApiService ({tfm})] Exited"); - App.AssertOutputContains(new Regex(@"dotnet watch ⌚ \[WatchAspire.ApiService \(net.*\)\] Process id [0-9]+ ran for [0-9]+ms and exited with exit code 0")); App.AssertOutputContains(MessageDescriptor.Building.GetMessage(serviceProjectPath)); App.AssertOutputContains("error CS0246: The type or namespace name 'WeatherForecast' could not be found"); @@ -1189,11 +1225,12 @@ public async Task Aspire_BuildError_ManualRestart() serviceSourcePath, serviceSource.Replace("WeatherForecast", "WeatherForecast2")); - await App.WaitForOutputLineContaining(MessageDescriptor.Capabilities, $"WatchAspire.ApiService ({tfm})"); + await App.WaitForOutputLineContaining(MessageDescriptor.ProjectsRestarted.GetMessage(1)); App.AssertOutputContains(MessageDescriptor.BuildSucceeded.GetMessage(serviceProjectPath)); App.AssertOutputContains(MessageDescriptor.ProjectsRebuilt); App.AssertOutputContains($"dotnet watch ⭐ Starting project: {serviceProjectPath}"); + App.Process.ClearOutput(); App.SendControlC(); @@ -1201,16 +1238,17 @@ public async Task Aspire_BuildError_ManualRestart() await App.WaitUntilOutputContains($"[WatchAspire.ApiService ({tfm})] Exited"); await App.WaitUntilOutputContains($"[WatchAspire.AppHost ({tfm})] Exited"); - await App.WaitUntilOutputContains(new Regex(@"dotnet watch ⌚ \[WatchAspire.ApiService \(net.*\)\] Process id [0-9]+ ran for [0-9]+ms and exited with exit code 0")); - await App.WaitUntilOutputContains(new Regex(@"dotnet watch ⌚ \[WatchAspire.AppHost \(net.*\)\] Process id [0-9]+ ran for [0-9]+ms and exited with exit code 0")); await App.WaitUntilOutputContains("dotnet watch ⭐ Waiting for server to shutdown ..."); App.AssertOutputContains("dotnet watch ⭐ Stop session #1"); - App.AssertOutputContains("dotnet watch ⭐ [#1] Sending 'sessionTerminated'"); + App.AssertOutputContains("dotnet watch ⭐ Stop session #2"); + App.AssertOutputContains("dotnet watch ⭐ Stop session #3"); + App.AssertOutputContains("dotnet watch ⭐ [#2] Sending 'sessionTerminated'"); + App.AssertOutputContains("dotnet watch ⭐ [#3] Sending 'sessionTerminated'"); } - [PlatformSpecificFact(TestPlatforms.Windows)] // "https://github.com/dotnet/sdk/issues/49307") + [PlatformSpecificFact(TestPlatforms.Windows)] // https://github.com/dotnet/aspnetcore/issues/63759 public async Task Aspire_NoEffect_AutoRestart() { var tfm = ToolsetInfo.CurrentTargetFramework; @@ -1226,18 +1264,32 @@ public async Task Aspire_NoEffect_AutoRestart() await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); // wait until after DCP sessions have been started for all projects: - await App.WaitUntilOutputContains("dotnet watch ⭐ Session started: #2"); + await App.WaitUntilOutputContains("dotnet watch ⭐ Session started: #3"); + + // other services are waiting for completion of MigrationService: + App.AssertOutputContains("dotnet watch ⭐ Session started: #1"); + App.AssertOutputContains(MessageDescriptor.Exited, $"WatchAspire.MigrationService ({tfm})"); + App.AssertOutputContains("dotnet watch ⭐ [#1] Sending 'sessionTerminated'"); + + // migration service output should not be printed to dotnet-watch output, it hsould be sent via DCP as a notification: + App.AssertOutputContains("dotnet watch ⭐ [#1] Sending 'serviceLogs': log_message=' Migration complete', is_std_err=False"); + App.AssertOutputDoesNotContain(new Regex("^ +Migration complete")); + App.Process.ClearOutput(); // no-effect edit: UpdateSourceFile(webSourcePath, src => src.Replace("/* top-level placeholder */", "builder.Services.AddRazorComponents();")); await App.WaitForOutputLineContaining(MessageDescriptor.HotReloadChangeHandled); - await App.WaitUntilOutputContains("dotnet watch ⭐ Session started: #2"); + await App.WaitUntilOutputContains("dotnet watch ⭐ Session started: #3"); App.AssertOutputContains(MessageDescriptor.ProjectsRestarted.GetMessage(1)); App.AssertOutputDoesNotContain("⚠"); + // The process exited and should not participate in Hot Reload: + App.AssertOutputDoesNotContain($"[WatchAspire.MigrationService ({tfm})]"); + App.AssertOutputDoesNotContain("dotnet watch ⭐ [#1]"); + App.Process.ClearOutput(); // lambda body edit: @@ -1245,9 +1297,13 @@ public async Task Aspire_NoEffect_AutoRestart() await App.WaitForOutputLineContaining(MessageDescriptor.HotReloadChangeHandled); App.AssertOutputContains($"dotnet watch 🕵️ [WatchAspire.Web ({tfm})] Updates applied."); - App.AssertOutputDoesNotContain("Projects rebuilt"); - App.AssertOutputDoesNotContain("Projects restarted"); + App.AssertOutputDoesNotContain(MessageDescriptor.ProjectsRebuilt); + App.AssertOutputDoesNotContain(MessageDescriptor.ProjectsRestarted); App.AssertOutputDoesNotContain("⚠"); + + // The process exited and should not participate in Hot Reload: + App.AssertOutputDoesNotContain($"[WatchAspire.MigrationService ({tfm})]"); + App.AssertOutputDoesNotContain("dotnet watch ⭐ [#1]"); } } } diff --git a/src/sdk/test/dotnet-watch.Tests/HotReload/CompilationHandlerTests.cs b/src/sdk/test/dotnet-watch.Tests/HotReload/CompilationHandlerTests.cs index bedd9d2a7c5..9ac5030c4eb 100644 --- a/src/sdk/test/dotnet-watch.Tests/HotReload/CompilationHandlerTests.cs +++ b/src/sdk/test/dotnet-watch.Tests/HotReload/CompilationHandlerTests.cs @@ -25,7 +25,7 @@ public async Task ReferenceOutputAssembly_False() var loggerFactory = new LoggerFactory(reporter); var logger = loggerFactory.CreateLogger("Test"); var projectGraph = ProjectGraphUtilities.TryLoadProjectGraph(options.ProjectPath, globalOptions: [], logger, projectGraphRequired: false, CancellationToken.None); - var handler = new CompilationHandler(loggerFactory, logger, processRunner); + var handler = new CompilationHandler(logger, processRunner); await handler.Workspace.UpdateProjectConeAsync(hostProject, CancellationToken.None); diff --git a/src/sdk/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs b/src/sdk/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs index 76993fbe54e..499c04e6883 100644 --- a/src/sdk/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs +++ b/src/sdk/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs @@ -78,6 +78,7 @@ private static async Task Launch(string projectPath, TestRuntime projectOptions, new CancellationTokenSource(), onOutput: null, + onExit: null, restartOperation: startOp!, cancellationToken); @@ -525,7 +526,7 @@ public async Task RudeEditInProjectWithoutRunningProcess() // Terminate the process: Log($"Terminating process {runningProject.ProjectNode.GetDisplayName()} ..."); - await w.Service.ProjectLauncher.TerminateProcessAsync(runningProject, CancellationToken.None); + await runningProject.TerminateAsync(isRestarting: false); // rude edit in A (changing assembly level attribute): UpdateSourceFile(serviceSourceA2, """ diff --git a/src/sdk/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs b/src/sdk/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs index 6f2b2fc7e30..aeaffc43f28 100644 --- a/src/sdk/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs +++ b/src/sdk/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs @@ -117,11 +117,11 @@ public static void Equal(T expected, T actual, IEqualityComparer? comparer if (expected == null) { - Fail("expected was null, but actual wasn't" + Environment.NewLine + message); + Fail("pattern was null, but actual wasn't" + Environment.NewLine + message); } else if (actual == null) { - Fail("actual was null, but expected wasn't" + Environment.NewLine + message); + Fail("actual was null, but pattern wasn't" + Environment.NewLine + message); } else if (!(comparer ?? AssertEqualityComparer.Instance).Equals(expected, actual)) { @@ -235,14 +235,25 @@ public static void EqualFileList(IEnumerable expectedFiles, IEnumerable< } public static void ContainsSubstring(string expected, IEnumerable items) + => AssertSubstringPresence(expected, items, expectedPresent: true); + + public static void DoesNotContainSubstring(string expected, IEnumerable items) + => AssertSubstringPresence(expected, items, expectedPresent: false); + + private static void AssertSubstringPresence(string expected, IEnumerable items, bool expectedPresent) { - if (items.Any(item => item.Contains(expected))) + if (items.Any(item => item.Contains(expected)) == expectedPresent) { return; } var message = new StringBuilder(); - message.AppendLine($"Expected output not found:"); + + + message.AppendLine(expectedPresent + ? "Expected text found in the output:" + : "Text not expected to be found in the output:"); + message.AppendLine(expected); message.AppendLine(); message.AppendLine("Actual output:"); @@ -256,15 +267,25 @@ public static void ContainsSubstring(string expected, IEnumerable items) } public static void ContainsPattern(Regex expected, IEnumerable items) + => AssertPatternPresence(expected, items, expectedPresent: true); + + public static void DoesNotContainPattern(Regex pattern, IEnumerable items) + => AssertPatternPresence(pattern, items, expectedPresent: false); + + private static void AssertPatternPresence(Regex pattern, IEnumerable items, bool expectedPresent) { - if (items.Any(item => expected.IsMatch(item))) + if (items.Any(item => pattern.IsMatch(item)) == expectedPresent) { return; } var message = new StringBuilder(); - message.AppendLine($"Expected pattern not found in the output:"); - message.AppendLine(expected.ToString()); + + message.AppendLine(expectedPresent + ? "Expected pattern found in the output:" + : "Pattern not expected to be found in the output:"); + + message.AppendLine(pattern.ToString()); message.AppendLine(); message.AppendLine("Actual output:"); diff --git a/src/sdk/test/dotnet-watch.Tests/TestUtilities/TestBrowserRefreshServer.cs b/src/sdk/test/dotnet-watch.Tests/TestUtilities/TestBrowserRefreshServer.cs new file mode 100644 index 00000000000..06acc9719b3 --- /dev/null +++ b/src/sdk/test/dotnet-watch.Tests/TestUtilities/TestBrowserRefreshServer.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.DotNet.HotReload; + +namespace Microsoft.DotNet.Watch.UnitTests; + +internal class TestBrowserRefreshServer(string middlewareAssemblyPath) + : AbstractBrowserRefreshServer(middlewareAssemblyPath, new TestLogger(), new TestLoggerFactory()) +{ + public Func? CreateAndStartHostImpl; + + protected override ValueTask CreateAndStartHostAsync(CancellationToken cancellationToken) + => ValueTask.FromResult((CreateAndStartHostImpl ?? throw new NotImplementedException())()); + + protected override bool SuppressTimeouts => true; +} diff --git a/src/sdk/test/dotnet-watch.Tests/TestUtilities/TestLogger.cs b/src/sdk/test/dotnet-watch.Tests/TestUtilities/TestLogger.cs index 3a9add553aa..5ae8e7dcd81 100644 --- a/src/sdk/test/dotnet-watch.Tests/TestUtilities/TestLogger.cs +++ b/src/sdk/test/dotnet-watch.Tests/TestUtilities/TestLogger.cs @@ -11,6 +11,8 @@ internal class TestLogger(ITestOutputHelper? output = null) : ILogger public readonly Lock Guard = new(); private readonly List _messages = []; + public Func? IsEnabledImpl; + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { var message = $"[{logLevel}] {formatter(state, exception)}"; @@ -36,5 +38,5 @@ public ImmutableArray GetAndClearMessages() where TState : notnull => throw new NotImplementedException(); public bool IsEnabled(LogLevel logLevel) - => true; + => IsEnabledImpl?.Invoke(logLevel) ?? true; } diff --git a/src/sdk/test/dotnet-watch.Tests/TestUtilities/TestLoggerFactory.cs b/src/sdk/test/dotnet-watch.Tests/TestUtilities/TestLoggerFactory.cs new file mode 100644 index 00000000000..be1e6968295 --- /dev/null +++ b/src/sdk/test/dotnet-watch.Tests/TestUtilities/TestLoggerFactory.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.Logging; + +namespace Microsoft.DotNet.Watch.UnitTests; + +internal class TestLoggerFactory(ITestOutputHelper? output = null) : ILoggerFactory +{ + public Func? CreateLoggerImpl; + + public ILogger CreateLogger(string categoryName) + => CreateLoggerImpl?.Invoke(categoryName) ?? new TestLogger(output); + + public void AddProvider(ILoggerProvider provider) {} + public void Dispose() { } +} diff --git a/src/sdk/test/dotnet-watch.Tests/TestUtilities/WatchableApp.cs b/src/sdk/test/dotnet-watch.Tests/TestUtilities/WatchableApp.cs index 8888b563439..81bfd17aae2 100644 --- a/src/sdk/test/dotnet-watch.Tests/TestUtilities/WatchableApp.cs +++ b/src/sdk/test/dotnet-watch.Tests/TestUtilities/WatchableApp.cs @@ -32,15 +32,21 @@ internal sealed class WatchableApp(DebugTestOutputLogger logger) : IDisposable public void AssertOutputContains(string message) => AssertEx.ContainsSubstring(message, Process.Output); - public void AssertOutputDoesNotContain(string message) - => Assert.DoesNotContain(Process.Output, line => line.Contains(message)); - public void AssertOutputContains(Regex pattern) => AssertEx.ContainsPattern(pattern, Process.Output); public void AssertOutputContains(MessageDescriptor descriptor, string projectDisplay = null) => AssertOutputContains(GetPattern(descriptor, projectDisplay)); + public void AssertOutputDoesNotContain(string message) + => AssertEx.DoesNotContainSubstring(message, Process.Output); + + public void AssertOutputDoesNotContain(Regex pattern) + => AssertEx.DoesNotContainPattern(pattern, Process.Output); + + public void AssertOutputDoesNotContain(MessageDescriptor descriptor, string projectDisplay = null) + => AssertOutputDoesNotContain(GetPattern(descriptor, projectDisplay)); + private static Regex GetPattern(MessageDescriptor descriptor, string projectDisplay = null) => new Regex(Regex.Replace(Regex.Escape((projectDisplay != null ? $"[{projectDisplay}] " : "") + descriptor.Format), @"\\\{[0-9]+\}", ".*")); @@ -203,5 +209,22 @@ public void SendKey(char c) Process.Process.StandardInput.Write(c); Process.Process.StandardInput.Flush(); } + + public void UseTestBrowser() + { + var path = GetTestBrowserPath(); + EnvironmentVariables.Add("DOTNET_WATCH_BROWSER_PATH", path); + + if (!OperatingSystem.IsWindows()) + { + File.SetUnixFileMode(path, UnixFileMode.UserExecute); + } + } + + public static string GetTestBrowserPath() + { + var exeExtension = OperatingSystem.IsWindows() ? ".exe" : string.Empty; + return Path.Combine(Path.GetDirectoryName(typeof(WatchableApp).Assembly.Location!)!, "test-browser", "dotnet-watch-test-browser" + exeExtension); + } } } diff --git a/src/sdk/test/dotnet-watch.Tests/Watch/BuildEvaluatorTests.cs b/src/sdk/test/dotnet-watch.Tests/Watch/BuildEvaluatorTests.cs index 1efccba2eb2..d673b618826 100644 --- a/src/sdk/test/dotnet-watch.Tests/Watch/BuildEvaluatorTests.cs +++ b/src/sdk/test/dotnet-watch.Tests/Watch/BuildEvaluatorTests.cs @@ -16,9 +16,11 @@ private static DotNetWatchContext CreateContext(bool suppressMSBuildIncrementali SuppressMSBuildIncrementalism = suppressMSBuildIncrementalism }; + var processOutputReporter = new TestProcessOutputReporter(); + return new DotNetWatchContext() { - ProcessOutputReporter = new TestProcessOutputReporter(), + ProcessOutputReporter = processOutputReporter, Logger = NullLogger.Instance, BuildLogger = NullLogger.Instance, LoggerFactory = NullLoggerFactory.Instance, @@ -26,7 +28,7 @@ private static DotNetWatchContext CreateContext(bool suppressMSBuildIncrementali Options = new(), RootProjectOptions = TestOptions.ProjectOptions, EnvironmentOptions = environmentOptions, - BrowserLauncher = new BrowserLauncher(NullLogger.Instance, environmentOptions), + BrowserLauncher = new BrowserLauncher(NullLogger.Instance, processOutputReporter, environmentOptions), BrowserRefreshServerFactory = new BrowserRefreshServerFactory() }; } diff --git a/src/sdk/test/dotnet-watch.Tests/Watch/NoRestoreTests.cs b/src/sdk/test/dotnet-watch.Tests/Watch/NoRestoreTests.cs index a28d91c3423..895a9d6b779 100644 --- a/src/sdk/test/dotnet-watch.Tests/Watch/NoRestoreTests.cs +++ b/src/sdk/test/dotnet-watch.Tests/Watch/NoRestoreTests.cs @@ -13,9 +13,11 @@ private static DotNetWatchContext CreateContext(string[] args = null, Environmen { environmentOptions ??= TestOptions.GetEnvironmentOptions(); + var processOutputReporter = new TestProcessOutputReporter(); + return new() { - ProcessOutputReporter = new TestProcessOutputReporter(), + ProcessOutputReporter = processOutputReporter, LoggerFactory = NullLoggerFactory.Instance, Logger = NullLogger.Instance, BuildLogger = NullLogger.Instance, @@ -23,7 +25,7 @@ private static DotNetWatchContext CreateContext(string[] args = null, Environmen Options = new(), RootProjectOptions = TestOptions.GetProjectOptions(args), EnvironmentOptions = environmentOptions, - BrowserLauncher = new BrowserLauncher(NullLogger.Instance, environmentOptions), + BrowserLauncher = new BrowserLauncher(NullLogger.Instance, processOutputReporter, environmentOptions), BrowserRefreshServerFactory = new BrowserRefreshServerFactory() }; } diff --git a/src/sdk/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj b/src/sdk/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj index 6a81d97e1ed..772d35b8051 100644 --- a/src/sdk/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj +++ b/src/sdk/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj @@ -16,10 +16,23 @@ --> + + + + + + <_Files>@(TestBrowserOutput->'%(RootDir)%(Directory)*.*') + + + <_FileItem Include="$(_Files)" /> + + + + diff --git a/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/FakeTelemetry.cs b/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/FakeTelemetry.cs index fe827527970..bcb6a6dbfde 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/FakeTelemetry.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/FakeTelemetry.cs @@ -9,8 +9,8 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests { public class FakeTelemetry : ITelemetry { - public bool Enabled { get; set; } - + public bool Enabled { get; set; } = true; + private readonly List _logEntries = new List(); public void TrackEvent(string eventName, IDictionary properties, IDictionary measurements) diff --git a/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenDotnetBuildInvocation.cs b/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenDotnetBuildInvocation.cs index 08c5ee7071c..8b6c7de5b07 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenDotnetBuildInvocation.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenDotnetBuildInvocation.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.DotNet.Cli.Commands.Restore; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Tests; using BuildCommand = Microsoft.DotNet.Cli.Commands.Build.BuildCommand; namespace Microsoft.DotNet.Cli.MSBuild.Tests @@ -10,8 +12,8 @@ namespace Microsoft.DotNet.Cli.MSBuild.Tests public class GivenDotnetBuildInvocation : IClassFixture { string[] ExpectedPrefix = ["-maxcpucount", "--verbosity:m", "-tlp:default=auto", "-nologo"]; - public static string[] RestoreExpectedPrefixForImplicitRestore = [..RestoringCommand.RestoreOptimizationProperties.Select(kvp => $"--restoreProperty:{kvp.Key}={kvp.Value}")]; - public static string[] RestoreExpectedPrefixForSeparateRestore = [..RestoringCommand.RestoreOptimizationProperties.Select(kvp => $"--property:{kvp.Key}={kvp.Value}")]; + public static string[] RestoreExpectedPrefixForImplicitRestore = [.. RestoringCommand.RestoreOptimizationProperties.Select(kvp => $"--restoreProperty:{kvp.Key}={kvp.Value}")]; + public static string[] RestoreExpectedPrefixForSeparateRestore = [.. RestoringCommand.RestoreOptimizationProperties.Select(kvp => $"--property:{kvp.Key}={kvp.Value}")]; const string NugetInteractiveProperty = "--property:NuGetInteractive=false"; @@ -118,5 +120,47 @@ public void MsbuildInvocationIsCorrectForSeparateRestore( .BeEquivalentTo([.. ExpectedPrefix, "-consoleloggerparameters:Summary", NugetInteractiveProperty, .. expectedAdditionalArgs]); }); } + + [Theory] + [MemberData(memberName: nameof(TelemetryCommonPropertiesTests.LLMTelemetryTestCases), MemberType =typeof(TelemetryCommonPropertiesTests))] + public void WhenLLMIsDetectedTLLiveUpdateIsDisabled(Dictionary? llmEnvVarsToSet, string? expectedLLMName) + { + CommandDirectoryContext.PerformActionWithBasePath(WorkingDirectory, () => + { + try + { + // Set environment variables to simulate LLM environment + if (llmEnvVarsToSet is not null) + { + foreach (var (key, value) in llmEnvVarsToSet) + { + Environment.SetEnvironmentVariable(key, value); + } + } + + var command = (RestoringCommand)BuildCommand.FromArgs([]); + + if (expectedLLMName is not null) + { + command.GetArgumentTokensToMSBuild().Should().Contain(Constants.TerminalLogger_DisableNodeDisplay); + } + else + { + command.GetArgumentTokensToMSBuild().Should().NotContain(Constants.TerminalLogger_DisableNodeDisplay); + } + } + finally + { + // Clear the environment variables after the test + if (llmEnvVarsToSet is not null) + { + foreach (var (key, value) in llmEnvVarsToSet) + { + Environment.SetEnvironmentVariable(key, null); + } + } + } + }); + } } } diff --git a/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs b/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs index 4820dba066c..eb5678178da 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs @@ -5,6 +5,7 @@ using Microsoft.Build.Framework; using Microsoft.DotNet.Cli.Commands.MSBuild; +using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Cli.MSBuild.Tests { @@ -44,6 +45,7 @@ public void ItDoesNotMasksExceptionTelemetry() MSBuildLogger.FormatAndSend(fakeTelemetry, telemetryEventArgs); + fakeTelemetry.LogEntry.Should().NotBeNull(); fakeTelemetry.LogEntry.EventName.Should().Be(MSBuildLogger.SdkTaskBaseCatchExceptionTelemetryEventName); fakeTelemetry.LogEntry.Properties.Keys.Count.Should().Be(2); fakeTelemetry.LogEntry.Properties["exceptionType"].Should().Be("System.Exception"); @@ -108,20 +110,109 @@ public void ItCanSendProperties() { "RuntimeIdentifier", "null"}, { "SelfContained", "null"}, { "UseApphost", "null"}, - { "OutputType", "Library"}, + { "OutputType", "Library"} } }; MSBuildLogger.FormatAndSend(fakeTelemetry, telemetryEventArgs); - fakeTelemetry.LogEntry.Properties.Should().BeEquivalentTo(new Dictionary + fakeTelemetry.LogEntry.Properties.Should().BeEquivalentTo(telemetryEventArgs.Properties); + } + + [Fact] + public void ItAggregatesEvents() + { + var fakeTelemetry = new FakeTelemetry(); + fakeTelemetry.Enabled = true; + var logger = new MSBuildLogger(fakeTelemetry); + + var event1 = new TelemetryEventArgs + { + EventName = MSBuildLogger.TaskFactoryTelemetryAggregatedEventName, + Properties = new Dictionary + { + { "AssemblyTaskFactoryTasksExecutedCount", "2" }, + { "RoslynCodeTaskFactoryTasksExecutedCount", "1" } + } + }; + + var event2 = new TelemetryEventArgs + { + EventName = MSBuildLogger.TaskFactoryTelemetryAggregatedEventName, + Properties = new Dictionary + { + { "AssemblyTaskFactoryTasksExecutedCount", "3" }, + { "CustomTaskFactoryTasksExecutedCount", "2" } + } + }; + + var event3 = new TelemetryEventArgs + { + EventName = MSBuildLogger.TasksTelemetryAggregatedEventName, + Properties = new Dictionary + { + { "TasksExecutedCount", "3" }, + { "TaskHostTasksExecutedCount", "2" } + } + }; + + var event4 = new TelemetryEventArgs + { + EventName = MSBuildLogger.TasksTelemetryAggregatedEventName, + Properties = new Dictionary + { + { "TasksExecutedCount", "5" } + } + }; + + logger.AggregateEvent(event1); + logger.AggregateEvent(event2); + logger.AggregateEvent(event3); + logger.AggregateEvent(event4); + + logger.SendAggregatedEventsOnBuildFinished(fakeTelemetry); + + fakeTelemetry.LogEntries.Should().HaveCount(2); + + var taskFactoryEntry = fakeTelemetry.LogEntries.FirstOrDefault(e => e.EventName == $"msbuild/{MSBuildLogger.TaskFactoryTelemetryAggregatedEventName}"); + taskFactoryEntry.Should().NotBeNull(); + taskFactoryEntry.Properties["AssemblyTaskFactoryTasksExecutedCount"].Should().Be("5"); // 2 + 3 + taskFactoryEntry.Properties["RoslynCodeTaskFactoryTasksExecutedCount"].Should().Be("1"); // 1 + 0 + taskFactoryEntry.Properties["CustomTaskFactoryTasksExecutedCount"].Should().Be("2"); // 0 + 2 + + var tasksEntry = fakeTelemetry.LogEntries.FirstOrDefault(e => e.EventName == $"msbuild/{MSBuildLogger.TasksTelemetryAggregatedEventName}"); + tasksEntry.Should().NotBeNull(); + tasksEntry.Properties["TasksExecutedCount"].Should().Be("8"); // 3 + 5 + tasksEntry.Properties["TaskHostTasksExecutedCount"].Should().Be("2"); // 2 + 0 + } + + [Fact] + public void ItIgnoresNonIntegerPropertiesDuringAggregation() + { + var fakeTelemetry = new FakeTelemetry(); + fakeTelemetry.Enabled = true; + var logger = new MSBuildLogger(fakeTelemetry); + + var eventArgs = new TelemetryEventArgs + { + EventName = MSBuildLogger.TaskFactoryTelemetryAggregatedEventName, + Properties = new Dictionary { - { "TargetFrameworkVersion", "9a871d7066260764d4cb5047e4b10570271d04bd1da275681a4b12bce0b27496"}, - { "RuntimeIdentifier", "fb329000228cc5a24c264c57139de8bf854fc86fc18bf1c04ab61a2b5cb4b921"}, - { "SelfContained", "fb329000228cc5a24c264c57139de8bf854fc86fc18bf1c04ab61a2b5cb4b921"}, - { "UseApphost", "fb329000228cc5a24c264c57139de8bf854fc86fc18bf1c04ab61a2b5cb4b921"}, - { "OutputType", "d77982267d9699c2a57bcab5bb975a1935f6427002f52fd4569762fd72db3a94"}, - }); + { "AssemblyTaskFactoryTasksExecutedCount", "3" }, + { "InvalidProperty", "not-a-number" }, + { "InvalidProperty2", "1.234" }, + } + }; + + logger.AggregateEvent(eventArgs); + + logger.SendAggregatedEventsOnBuildFinished(fakeTelemetry); + + fakeTelemetry.LogEntry.Should().NotBeNull(); + fakeTelemetry.LogEntry.EventName.Should().Be($"msbuild/{MSBuildLogger.TaskFactoryTelemetryAggregatedEventName}"); + fakeTelemetry.LogEntry.Properties["AssemblyTaskFactoryTasksExecutedCount"].Should().Be("3"); + fakeTelemetry.LogEntry.Properties.Should().NotContainKey("InvalidProperty"); + fakeTelemetry.LogEntry.Properties.Should().NotContainKey("InvalidProperty2"); } [Fact] diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Package/Add/GivenDotnetPackageAdd.cs b/src/sdk/test/dotnet.Tests/CommandTests/Package/Add/GivenDotnetPackageAdd.cs index c924c1ac65b..4bfa8890355 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/Package/Add/GivenDotnetPackageAdd.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/Package/Add/GivenDotnetPackageAdd.cs @@ -290,16 +290,45 @@ public void VersionRange(bool asArgument) cmd.StdErr.Should().BeEmpty(); } - [Fact] - public void FileBasedApp() + private string[]? GetFileBasedAppArgs(bool legacyForm, bool? versionOption, bool fileOption, bool noRestore, string packageName = "Humanizer") { + if (!legacyForm && !fileOption) + { + Log.WriteLine("Skipping invalid combination of parameters"); + return null; + } + + (string, string) commandArgs = legacyForm + ? ("add", "package") + : ("package", "add"); + + return [ + commandArgs.Item1, + .. (ReadOnlySpan)(fileOption ? [] : ["Program.cs"]), + commandArgs.Item2, + .. (ReadOnlySpan)(versionOption switch + { + true => [packageName, "--version", "2.14.1"], + false => [$"{packageName}@2.14.1"], + null => [packageName], + }), + .. (ReadOnlySpan)(fileOption ? ["--file", "Program.cs"] : []), + .. (ReadOnlySpan)(noRestore ? ["--no-restore"] : []), + ]; + } + + [Theory, CombinatorialData] + public void FileBasedApp(bool legacyForm, bool versionOption, bool fileOption, bool noRestore) + { + if (GetFileBasedAppArgs(legacyForm, versionOption, fileOption, noRestore) is not { } args) return; + var testInstance = _testAssetsManager.CreateTestDirectory(); var file = Path.Join(testInstance.Path, "Program.cs"); File.WriteAllText(file, """ Console.WriteLine(); """); - new DotnetCommand(Log, "package", "add", "Humanizer@2.14.1", "--file", "Program.cs") + new DotnetCommand(Log, args) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Pass(); @@ -311,12 +340,13 @@ public void FileBasedApp() """); } - [Theory] - [InlineData("Humanizer")] - [InlineData("humanizer")] + [Theory, CombinatorialData] public void FileBasedApp_ReplaceExisting( - string sourceFilePackageId) + [CombinatorialValues("Humanizer", "humanizer")] string sourceFilePackageId, + bool legacyForm, bool versionOption, bool fileOption, bool noRestore) { + if (GetFileBasedAppArgs(legacyForm, versionOption, fileOption, noRestore) is not { } args) return; + var testInstance = _testAssetsManager.CreateTestDirectory(); var file = Path.Join(testInstance.Path, "Program.cs"); File.WriteAllText(file, $""" @@ -324,7 +354,7 @@ public void FileBasedApp_ReplaceExisting( Console.WriteLine(); """); - new DotnetCommand(Log, "package", "add", "Humanizer@2.14.1", "--file", "Program.cs") + new DotnetCommand(Log, args) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Pass(); @@ -400,16 +430,18 @@ public void FileBasedApp_NoVersion_Prerelease(string[] inputVersions, string? _, """); } - [Fact] - public void FileBasedApp_NoVersionAndNoRestore() + [Theory, CombinatorialData] + public void FileBasedApp_NoVersionAndNoRestore(bool legacyForm, bool fileOption) { + if (GetFileBasedAppArgs(legacyForm, versionOption: null, fileOption, noRestore: true) is not { } args) return; + var testInstance = _testAssetsManager.CreateTestDirectory(); var file = Path.Join(testInstance.Path, "Program.cs"); File.WriteAllText(file, """ Console.WriteLine(); """); - new DotnetCommand(Log, "package", "add", "Humanizer", "--file", "Program.cs", "--no-restore") + new DotnetCommand(Log, args) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Pass(); @@ -421,9 +453,11 @@ public void FileBasedApp_NoVersionAndNoRestore() """); } - [Fact] - public void FileBasedApp_VersionAndPrerelease() + [Theory, CombinatorialData] + public void FileBasedApp_VersionAndPrerelease(bool legacyForm, bool versionOption, bool fileOption, bool noRestore) { + if (GetFileBasedAppArgs(legacyForm, versionOption, fileOption, noRestore) is not { } args) return; + var testInstance = _testAssetsManager.CreateTestDirectory(); var file = Path.Join(testInstance.Path, "Program.cs"); var source = """ @@ -431,7 +465,7 @@ public void FileBasedApp_VersionAndPrerelease() """; File.WriteAllText(file, source); - new DotnetCommand(Log, "package", "add", "Humanizer@2.14.1", "--file", "Program.cs", "--prerelease") + new DotnetCommand(Log, [.. args, "--prerelease"]) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Fail() @@ -440,9 +474,11 @@ public void FileBasedApp_VersionAndPrerelease() File.ReadAllText(file).Should().Be(source); } - [Fact] - public void FileBasedApp_InvalidPackage() + [Theory, CombinatorialData] + public void FileBasedApp_InvalidPackage(bool legacyForm, bool fileOption) { + if (GetFileBasedAppArgs(legacyForm, versionOption: null, fileOption, noRestore: false, packageName: "Microsoft.ThisPackageDoesNotExist") is not { } args) return; + var testInstance = _testAssetsManager.CreateTestDirectory(); var file = Path.Join(testInstance.Path, "Program.cs"); var source = """ @@ -450,7 +486,7 @@ public void FileBasedApp_InvalidPackage() """; File.WriteAllText(file, source); - new DotnetCommand(Log, "package", "add", "Microsoft.ThisPackageDoesNotExist", "--file", "Program.cs") + new DotnetCommand(Log, args) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Fail(); @@ -458,16 +494,18 @@ public void FileBasedApp_InvalidPackage() File.ReadAllText(file).Should().Be(source); } - [Fact] - public void FileBasedApp_InvalidPackage_NoRestore() + [Theory, CombinatorialData] + public void FileBasedApp_InvalidPackage_NoRestore(bool legacyForm, bool fileOption) { + if (GetFileBasedAppArgs(legacyForm, versionOption: null, fileOption, noRestore: true, packageName: "Microsoft.ThisPackageDoesNotExist") is not { } args) return; + var testInstance = _testAssetsManager.CreateTestDirectory(); var file = Path.Join(testInstance.Path, "Program.cs"); File.WriteAllText(file, """ Console.WriteLine(); """); - new DotnetCommand(Log, "package", "add", "Microsoft.ThisPackageDoesNotExist", "--file", "Program.cs", "--no-restore") + new DotnetCommand(Log, args) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Pass(); @@ -479,9 +517,11 @@ public void FileBasedApp_InvalidPackage_NoRestore() """); } - [Fact] - public void FileBasedApp_CentralPackageManagement() + [Theory, CombinatorialData] + public void FileBasedApp_CentralPackageManagement(bool legacyForm, bool versionOption, bool fileOption, bool noRestore) { + if (GetFileBasedAppArgs(legacyForm, versionOption, fileOption, noRestore) is not { } args) return; + var testInstance = _testAssetsManager.CreateTestDirectory(); var file = Path.Join(testInstance.Path, "Program.cs"); var source = """ @@ -498,7 +538,7 @@ public void FileBasedApp_CentralPackageManagement() """); - new DotnetCommand(Log, "package", "add", "Humanizer@2.14.1", "--file", "Program.cs") + new DotnetCommand(Log, args) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Pass(); @@ -522,8 +562,10 @@ public void FileBasedApp_CentralPackageManagement() } [Theory, CombinatorialData] - public void FileBasedApp_CentralPackageManagement_ReplaceExisting(bool wasInFile) + public void FileBasedApp_CentralPackageManagement_ReplaceExisting(bool wasInFile, bool legacyForm, bool versionOption, bool fileOption, bool noRestore) { + if (GetFileBasedAppArgs(legacyForm, versionOption, fileOption, noRestore) is not { } args) return; + var testInstance = _testAssetsManager.CreateTestDirectory(); var file = Path.Join(testInstance.Path, "Program.cs"); var source = """ @@ -553,7 +595,7 @@ public void FileBasedApp_CentralPackageManagement_ReplaceExisting(bool wasInFile """); - new DotnetCommand(Log, "package", "add", "Humanizer@2.14.1", "--file", "Program.cs") + new DotnetCommand(Log, args) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Pass(); @@ -576,9 +618,11 @@ public void FileBasedApp_CentralPackageManagement_ReplaceExisting(bool wasInFile """); } - [Fact] - public void FileBasedApp_CentralPackageManagement_NoVersionSpecified() + [Theory, CombinatorialData] + public void FileBasedApp_CentralPackageManagement_NoVersionSpecified(bool legacyForm, bool fileOption) { + if (GetFileBasedAppArgs(legacyForm, versionOption: null, fileOption, noRestore: false, packageName: "A") is not { } args) return; + var testInstance = _testAssetsManager.CreateTestDirectory(); string[] versions = ["0.0.5", "0.9.0", "1.0.0-preview.3"]; @@ -602,7 +646,7 @@ public void FileBasedApp_CentralPackageManagement_NoVersionSpecified() """); - new DotnetCommand(Log, "package", "add", "A", "--file", "Program.cs") + new DotnetCommand(Log, args) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Pass(); @@ -624,9 +668,11 @@ public void FileBasedApp_CentralPackageManagement_NoVersionSpecified() """); } - [Fact] - public void FileBasedApp_CentralPackageManagement_NoVersionSpecified_KeepExisting() + [Theory, CombinatorialData] + public void FileBasedApp_CentralPackageManagement_NoVersionSpecified_KeepExisting(bool legacyForm, bool fileOption, bool noRestore) { + if (GetFileBasedAppArgs(legacyForm, versionOption: null, fileOption, noRestore) is not { } args) return; + var testInstance = _testAssetsManager.CreateTestDirectory(); var file = Path.Join(testInstance.Path, "Program.cs"); var source = """ @@ -648,7 +694,7 @@ public void FileBasedApp_CentralPackageManagement_NoVersionSpecified_KeepExistin """; File.WriteAllText(directoryPackagesProps, directoryPackagesPropsSource); - new DotnetCommand(Log, "package", "add", "Humanizer", "--file", "Program.cs") + new DotnetCommand(Log, args) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Pass(); diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs b/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs index 507d36c0da9..90763462aeb 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Immutable; using System.Security; using System.Text.RegularExpressions; using Microsoft.CodeAnalysis.Text; @@ -58,9 +59,13 @@ public void SameAsTemplate() var dotnetProjectConvertProjectText = File.ReadAllText(dotnetProjectConvertProject); var dotnetNewConsoleProjectText = File.ReadAllText(dotnetNewConsoleProject); - // There are some differences: we add PublishAot=true and UserSecretsId. + // There are some differences: we add PublishAot=true, PackAsTool=true, and UserSecretsId. var patchedDotnetProjectConvertProjectText = dotnetProjectConvertProjectText - .Replace(" true" + Environment.NewLine, string.Empty); + .Replace(""" + true + true + + """, string.Empty); patchedDotnetProjectConvertProjectText = Regex.Replace(patchedDotnetProjectConvertProjectText, """ [^<]*<\/UserSecretsId>""" + Environment.NewLine, string.Empty); @@ -68,6 +73,125 @@ public void SameAsTemplate() .And.StartWith(""""""); } + [Theory] // https://github.com/dotnet/sdk/issues/50832 + [InlineData("File", "Lib", "../Lib", "Project", "../Lib/lib.csproj")] + [InlineData(".", "Lib", "./Lib", "Project", "../Lib/lib.csproj")] + [InlineData(".", "Lib", "Lib/../Lib", "Project", "../Lib/lib.csproj")] + [InlineData("File", "Lib", "../Lib", "File/Project", "../../Lib/lib.csproj")] + [InlineData("File", "Lib", "..\\Lib", "File/Project", "../../Lib/lib.csproj")] + public void ProjectReference_RelativePaths(string fileDir, string libraryDir, string reference, string outputDir, string convertedReference) + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + + var libraryDirFullPath = Path.Join(testInstance.Path, libraryDir); + Directory.CreateDirectory(libraryDirFullPath); + File.WriteAllText(Path.Join(libraryDirFullPath, "lib.cs"), """ + public static class C + { + public static void M() + { + System.Console.WriteLine("Hello from library"); + } + } + """); + File.WriteAllText(Path.Join(libraryDirFullPath, "lib.csproj"), $""" + + + {ToolsetInfo.CurrentTargetFramework} + + + """); + + var fileDirFullPath = Path.Join(testInstance.Path, fileDir); + Directory.CreateDirectory(fileDirFullPath); + File.WriteAllText(Path.Join(fileDirFullPath, "app.cs"), $""" + #:project {reference} + C.M(); + """); + + var expectedOutput = "Hello from library"; + + new DotnetCommand(Log, "run", "app.cs") + .WithWorkingDirectory(fileDirFullPath) + .Execute() + .Should().Pass() + .And.HaveStdOut(expectedOutput); + + var outputDirFullPath = Path.Join(testInstance.Path, outputDir); + new DotnetCommand(Log, "project", "convert", "app.cs", "-o", outputDirFullPath) + .WithWorkingDirectory(fileDirFullPath) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run") + .WithWorkingDirectory(outputDirFullPath) + .Execute() + .Should().Pass() + .And.HaveStdOut(expectedOutput); + + File.ReadAllText(Path.Join(outputDirFullPath, "app.csproj")) + .Should().Contain($""" + + """); + } + + [Fact] // https://github.com/dotnet/sdk/issues/50832 + public void ProjectReference_FullPath() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + + var libraryDirFullPath = Path.Join(testInstance.Path, "Lib"); + Directory.CreateDirectory(libraryDirFullPath); + File.WriteAllText(Path.Join(libraryDirFullPath, "lib.cs"), """ + public static class C + { + public static void M() + { + System.Console.WriteLine("Hello from library"); + } + } + """); + File.WriteAllText(Path.Join(libraryDirFullPath, "lib.csproj"), $""" + + + {ToolsetInfo.CurrentTargetFramework} + + + """); + + var fileDirFullPath = Path.Join(testInstance.Path, "File"); + Directory.CreateDirectory(fileDirFullPath); + File.WriteAllText(Path.Join(fileDirFullPath, "app.cs"), $""" + #:project {libraryDirFullPath} + C.M(); + """); + + var expectedOutput = "Hello from library"; + + new DotnetCommand(Log, "run", "app.cs") + .WithWorkingDirectory(fileDirFullPath) + .Execute() + .Should().Pass() + .And.HaveStdOut(expectedOutput); + + var outputDirFullPath = Path.Join(testInstance.Path, "File/Project"); + new DotnetCommand(Log, "project", "convert", "app.cs", "-o", outputDirFullPath) + .WithWorkingDirectory(fileDirFullPath) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run") + .WithWorkingDirectory(outputDirFullPath) + .Execute() + .Should().Pass() + .And.HaveStdOut(expectedOutput); + + File.ReadAllText(Path.Join(outputDirFullPath, "app.csproj")) + .Should().Contain($""" + + """); + } + [Fact] public void DirectoryAlreadyExists() { @@ -661,6 +785,7 @@ public void ProcessingSucceeds() enable enable true + true Program-* @@ -708,6 +833,7 @@ public void UserSecretsId_Overridden_ViaDirective(bool hasDirectiveBuildProps) enable enable true + true MyIdFromDirective @@ -747,6 +873,7 @@ public void UserSecretsId_Overridden_ViaDirectoryBuildProps() enable enable true + true @@ -791,6 +918,7 @@ public void UserSecretsId_Overridden_SameAsImplicit(bool hasDirective, bool hasD enable enable true + true {(hasDirective ? SecurityElement.Escape(implicitValue) : "Program-*")} @@ -822,6 +950,7 @@ public void Directives() enable enable true + true net472 preview @@ -852,6 +981,7 @@ public void Directives_AllDefaultOverridden() #:property TargetFramework=net472 #:property Nullable=disable #:property PublishAot=false + #:property PackAsTool=false #:property Custom=1 #:property ImplicitUsings=disable Console.WriteLine(); @@ -864,6 +994,7 @@ public void Directives_AllDefaultOverridden() net472 disable false + false 1 disable @@ -893,6 +1024,7 @@ public void Directives_Variable() enable enable true + true MyValue @@ -930,6 +1062,7 @@ public void Directives_DirectoryPath() enable enable true + true @@ -968,6 +1101,7 @@ public void Directives_Separators() enable enable true + true One=a/b Two/a=b @@ -1035,10 +1169,10 @@ public void Directives_InvalidPropertyName() { VerifyConversionThrows( inputCSharp: """ - #:property Name"=Value + #:property 123Name=Value """, expectedWildcardPattern: RunFileTests.DirectiveError("/app/Program.cs", 1, CliCommandStrings.PropertyDirectiveInvalidName, """ - The '"' character, hexadecimal value 0x22, cannot be included in a name. + Name cannot begin with the '1' character, hexadecimal value 0x31. """)); } @@ -1065,11 +1199,14 @@ public void Directives_Escaping() VerifyConversion( inputCSharp: """ #:property Prop= - #:sdk @="<>test - #:package @="<>test + #:sdk @="<>te'st + #:package @="<>te'st + #:property Pro'p=Single' + #:property Prop2=\"Value\" + #:property Prop3='Value' """, expectedProject: $""" - + Exe @@ -1077,17 +1214,31 @@ public void Directives_Escaping() enable enable true + true <test"> + \"Value\" + 'Value' - + """, - expectedCSharp: ""); + expectedCSharp: """ + #:property Pro'p=Single' + + """, + expectedErrors: + [ + (1, CliCommandStrings.QuoteInDirective), + (2, CliCommandStrings.QuoteInDirective), + (3, CliCommandStrings.QuoteInDirective), + (4, string.Format(CliCommandStrings.PropertyDirectiveInvalidName, "The ''' character, hexadecimal value 0x27, cannot be included in a name.")), + (5, CliCommandStrings.QuoteInDirective), + ]); } [Fact] @@ -1111,6 +1262,7 @@ public void Directives_Whitespace() enable enable true + true Value "My package with spaces" @@ -1122,7 +1274,11 @@ public void Directives_Whitespace() # ! /test #! /program x # :property Name=Value - """); + """, + expectedErrors: + [ + (3, CliCommandStrings.QuoteInDirective), + ]); } [Fact] @@ -1137,6 +1293,7 @@ public void Directives_BlankLines() enable enable true + true @@ -1202,6 +1359,7 @@ public void Directives_AfterToken() enable enable true + true 1 2 @@ -1248,6 +1406,7 @@ public void Directives_AfterIf() enable enable true + true 1 2 @@ -1291,6 +1450,7 @@ public void Directives_Comments() enable enable true + true 1 2 @@ -1398,6 +1558,7 @@ public void Directives_VersionedSdkFirst() enable enable true + true @@ -1408,10 +1569,15 @@ public void Directives_VersionedSdkFirst() """); } - private static void Convert(string inputCSharp, out string actualProject, out string? actualCSharp, bool force, string? filePath) + private const string programPath = "/app/Program.cs"; + + private static void Convert(string inputCSharp, out string actualProject, out string? actualCSharp, bool force, string? filePath, + bool collectDiagnostics, out ImmutableArray.Builder? actualDiagnostics) { - var sourceFile = new SourceFile(filePath ?? "/app/Program.cs", SourceText.From(inputCSharp, Encoding.UTF8)); - var directives = VirtualProjectBuildingCommand.FindDirectives(sourceFile, reportAllErrors: !force, DiagnosticBag.ThrowOnFirst()); + var sourceFile = new SourceFile(filePath ?? programPath, SourceText.From(inputCSharp, Encoding.UTF8)); + actualDiagnostics = null; + var diagnosticBag = collectDiagnostics ? DiagnosticBag.Collect(out actualDiagnostics) : DiagnosticBag.ThrowOnFirst(); + var directives = VirtualProjectBuildingCommand.FindDirectives(sourceFile, reportAllErrors: !force, diagnosticBag); var projectWriter = new StringWriter(); VirtualProjectBuildingCommand.WriteProjectFile(projectWriter, directives, isVirtualProject: false); actualProject = projectWriter.ToString(); @@ -1421,25 +1587,43 @@ private static void Convert(string inputCSharp, out string actualProject, out st /// /// means the conversion should not touch the C# content. /// - private static void VerifyConversion(string inputCSharp, string expectedProject, string? expectedCSharp, bool force = false, string? filePath = null) + private static void VerifyConversion(string inputCSharp, string expectedProject, string? expectedCSharp, bool force = false, string? filePath = null, + IEnumerable<(int LineNumber, string Message)>? expectedErrors = null) { - Convert(inputCSharp, out var actualProject, out var actualCSharp, force: force, filePath: filePath); + Convert(inputCSharp, out var actualProject, out var actualCSharp, force: force, filePath: filePath, + collectDiagnostics: expectedErrors != null, out var actualDiagnostics); actualProject.Should().Be(expectedProject); actualCSharp.Should().Be(expectedCSharp); + VerifyErrors(actualDiagnostics, expectedErrors); } private static void VerifyConversionThrows(string inputCSharp, string expectedWildcardPattern) { - var convert = () => Convert(inputCSharp, out _, out _, force: false, filePath: null); + var convert = () => Convert(inputCSharp, out _, out _, force: false, filePath: null, collectDiagnostics: false, out _); convert.Should().Throw().WithMessage(expectedWildcardPattern); } private static void VerifyDirectiveConversionErrors(string inputCSharp, IEnumerable<(int LineNumber, string Message)> expectedErrors) { - var programPath = "/app/Program.cs"; var sourceFile = new SourceFile(programPath, SourceText.From(inputCSharp, Encoding.UTF8)); VirtualProjectBuildingCommand.FindDirectives(sourceFile, reportAllErrors: true, DiagnosticBag.Collect(out var diagnostics)); - Assert.All(diagnostics, d => { Assert.Equal(programPath, d.Location.Path); }); - diagnostics.Select(d => (d.Location.Span.Start.Line + 1, d.Message)).Should().BeEquivalentTo(expectedErrors); + VerifyErrors(diagnostics, expectedErrors); + } + + private static void VerifyErrors(ImmutableArray.Builder? actual, IEnumerable<(int LineNumber, string Message)>? expected) + { + if (actual is null) + { + Assert.Null(expected); + } + else if (expected is null) + { + Assert.Null(actual); + } + else + { + Assert.All(actual, d => { Assert.Equal(programPath, d.Location.Path); }); + actual.Select(d => (d.Location.Span.Start.Line + 1, d.Message)).Should().BeEquivalentTo(expected); + } } } diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Run/FileBasedAppSourceEditorTests.cs b/src/sdk/test/dotnet.Tests/CommandTests/Run/FileBasedAppSourceEditorTests.cs index ea2480b032f..371b29d7f31 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/Run/FileBasedAppSourceEditorTests.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/Run/FileBasedAppSourceEditorTests.cs @@ -347,6 +347,45 @@ public void GroupWithoutSpace() """)); } + /// + /// New package directive should be sorted into the correct location in the package group. + /// + [Fact] + public void Sort() + { + Verify( + """ + #:property X=Y + #:package B@C + #:package X@Y + #:project D + #:package E + + Console.WriteLine(); + """, + (static editor => editor.Add(new CSharpDirective.Package(default) { Name = "Test", Version = "1.0.0" }), + """ + #:property X=Y + #:package B@C + #:package Test@1.0.0 + #:package X@Y + #:project D + #:package E + + Console.WriteLine(); + """), + (static editor => editor.Remove(editor.Directives[2]), + """ + #:property X=Y + #:package B@C + #:package X@Y + #:project D + #:package E + + Console.WriteLine(); + """)); + } + [Fact] public void OtherDirectives() { @@ -371,6 +410,33 @@ public void OtherDirectives() """)); } + /// + /// Shebang directive should always stay first. + /// + [Fact] + public void Shebang() + { + Verify( + """ + #!/test + Console.WriteLine(); + """, + (static editor => editor.Add(new CSharpDirective.Package(default) { Name = "MyPackage", Version = "1.0.0" }), + """ + #!/test + + #:package MyPackage@1.0.0 + + Console.WriteLine(); + """), + (static editor => editor.Remove(editor.Directives[1]), + """ + #!/test + + Console.WriteLine(); + """)); + } + [Fact] public void AfterTokens() { diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs b/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs index 3ecc85f0558..541788369fb 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs @@ -332,10 +332,10 @@ public void FilePath_AsProjectArgument() ///
[Theory] // error MSB1003: Specify a project or solution file. The current working directory does not contain a project or solution file. - [InlineData("build", "MSB1003")] + [InlineData("build", "MSB1003", false)] // dotnet watch: Could not find a MSBuild project file in '...'. Specify which project to use with the --project option. - [InlineData("watch", "--project")] - public void Precedence_BuiltInCommand(string cmd, string error) + [InlineData("watch", "--project", true)] + public void Precedence_BuiltInCommand(string cmd, string error, bool errorInStdErr) { var testInstance = _testAssetsManager.CreateTestDirectory(); File.WriteAllText(Path.Join(testInstance.Path, cmd), """ @@ -348,18 +348,26 @@ public void Precedence_BuiltInCommand(string cmd, string error) """); // dotnet build -> built-in command - new DotnetCommand(Log, cmd) + var failure = new DotnetCommand(Log, cmd) .WithWorkingDirectory(testInstance.Path) .Execute() - .Should().Fail() - .And.HaveStdOutContaining(error); + .Should().Fail(); + + if (errorInStdErr) + { + failure.And.HaveStdErrContaining(error); + } + else + { + failure.And.HaveStdOutContaining(error); + } // dotnet ./build -> file-based app new DotnetCommand(Log, $"./{cmd}") - .WithWorkingDirectory(testInstance.Path) - .Execute() - .Should().Pass() - .And.HaveStdOut("hello 1"); + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass() + .And.HaveStdOut("hello 1"); // dotnet run build -> file-based app new DotnetCommand(Log, "run", cmd) @@ -870,6 +878,128 @@ public void DirectoryBuildProps() .And.HaveStdOut("Hello from TestName"); } + /// + /// Overriding default (implicit) properties of file-based apps via implicit build files. + /// + [Fact] + public void DefaultProps_DirectoryBuildProps() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ + Console.WriteLine("Hi"); + """); + File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ + + + disable + + + """); + + new DotnetCommand(Log, "run", "Program.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Fail() + // error CS0103: The name 'Console' does not exist in the current context + .And.HaveStdOutContaining("error CS0103"); + + // Converting to a project should not change the behavior. + + new DotnetCommand(Log, "project", "convert", "Program.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run") + .WithWorkingDirectory(Path.Join(testInstance.Path, "Program")) + .Execute() + .Should().Fail() + // error CS0103: The name 'Console' does not exist in the current context + .And.HaveStdOutContaining("error CS0103"); + } + + /// + /// Overriding default (implicit) properties of file-based apps from custom SDKs. + /// + [Fact] + public void DefaultProps_CustomSdk() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + + var sdkDir = Path.Join(testInstance.Path, "MySdk"); + Directory.CreateDirectory(sdkDir); + File.WriteAllText(Path.Join(sdkDir, "Sdk.props"), """ + + + disable + + + """); + File.WriteAllText(Path.Join(sdkDir, "Sdk.targets"), """ + + """); + File.WriteAllText(Path.Join(sdkDir, "MySdk.csproj"), $""" + + + {ToolsetInfo.CurrentTargetFramework} + MSBuildSdk + false + + + + + + """); + + new DotnetCommand(Log, "pack") + .WithWorkingDirectory(sdkDir) + .Execute() + .Should().Pass(); + + var appDir = Path.Join(testInstance.Path, "app"); + Directory.CreateDirectory(appDir); + File.WriteAllText(Path.Join(appDir, "NuGet.config"), $""" + + + + + + + """); + File.WriteAllText(Path.Join(appDir, "Program.cs"), """ + #:sdk Microsoft.NET.Sdk + #:sdk MySdk@1.0.0 + Console.WriteLine("Hi"); + """); + + // Use custom package cache to avoid reuse of the custom SDK packed by previous test runs. + var packagesDir = Path.Join(testInstance.Path, ".packages"); + + new DotnetCommand(Log, "run", "Program.cs") + .WithEnvironmentVariable("NUGET_PACKAGES", packagesDir) + .WithWorkingDirectory(appDir) + .Execute() + .Should().Fail() + // error CS0103: The name 'Console' does not exist in the current context + .And.HaveStdOutContaining("error CS0103"); + + // Converting to a project should not change the behavior. + + new DotnetCommand(Log, "project", "convert", "Program.cs") + .WithEnvironmentVariable("NUGET_PACKAGES", packagesDir) + .WithWorkingDirectory(appDir) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run") + .WithEnvironmentVariable("NUGET_PACKAGES", packagesDir) + .WithWorkingDirectory(Path.Join(appDir, "Program")) + .Execute() + .Should().Fail() + // error CS0103: The name 'Console' does not exist in the current context + .And.HaveStdOutContaining("error CS0103"); + } + [Fact] public void ComputeRunArguments_Success() { @@ -1695,7 +1825,6 @@ public void Pack() var testInstance = _testAssetsManager.CreateTestDirectory(); var programFile = Path.Join(testInstance.Path, "MyFileBasedTool.cs"); File.WriteAllText(programFile, """ - #:property PackAsTool=true Console.WriteLine($"Hello; EntryPointFilePath set? {AppContext.GetData("EntryPointFilePath") is string}"); #if !DEBUG Console.WriteLine("Release config"); @@ -1742,7 +1871,6 @@ public void Pack_CustomPath() var testInstance = _testAssetsManager.CreateTestDirectory(); var programFile = Path.Join(testInstance.Path, "MyFileBasedTool.cs"); File.WriteAllText(programFile, """ - #:property PackAsTool=true #:property PackageOutputPath=custom Console.WriteLine($"Hello; EntryPointFilePath set? {AppContext.GetData("EntryPointFilePath") is string}"); """); @@ -2789,11 +2917,15 @@ public void UpToDate_InvalidOptions() /// /// Up-to-date checks and optimizations currently don't support other included files. /// - [Fact] - public void UpToDate_DefaultItems() + [Theory, CombinatorialData] // https://github.com/dotnet/sdk/issues/50912 + public void UpToDate_DefaultItems(bool optOut) { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), s_programReadingEmbeddedResource); + var code = $""" + {(optOut ? "#:property FileBasedProgramCanSkipMSBuild=false" : "")} + {s_programReadingEmbeddedResource} + """; + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), code); File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx); Build(testInstance, BuildLevel.All, expectedOutput: "[MyString, TestValue]"); @@ -2801,12 +2933,81 @@ public void UpToDate_DefaultItems() // Update the RESX file. File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx.Replace("TestValue", "UpdatedValue")); - Build(testInstance, BuildLevel.None, expectedOutput: "[MyString, TestValue]"); // note: outdated output (build skipped) + Build(testInstance, optOut ? BuildLevel.All : BuildLevel.None, expectedOutput: optOut ? "[MyString, UpdatedValue]" : "[MyString, TestValue]"); // note: outdated output (build skipped) + + // Update the C# file. + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), "//v2\n" + code); + + Build(testInstance, optOut ? BuildLevel.All : BuildLevel.Csc, expectedOutput: optOut ? "[MyString, UpdatedValue]" : "[MyString, TestValue]"); // note: outdated output (only CSC used) + + Build(testInstance, BuildLevel.All, ["--no-cache"], expectedOutput: "[MyString, UpdatedValue]"); + } + + /// + /// Combination of with optimization. + /// + [Theory, CombinatorialData] // https://github.com/dotnet/sdk/issues/50912 + public void UpToDate_DefaultItems_CscOnly(bool optOut) + { + var testInstance = _testAssetsManager.CreateTestDirectory(baseDirectory: OutOfTreeBaseDirectory); + var code = $""" + {(optOut ? "#:property FileBasedProgramCanSkipMSBuild=false" : "")} + {s_programReadingEmbeddedResource} + """; + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), code); + File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx); + + Build(testInstance, optOut ? BuildLevel.All : BuildLevel.Csc, expectedOutput: optOut ? "[MyString, TestValue]" : "Resource not found"); + + // Update the RESX file. + File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx.Replace("TestValue", "UpdatedValue")); + + Build(testInstance, optOut ? BuildLevel.All : BuildLevel.None, expectedOutput: optOut ? "[MyString, UpdatedValue]" : "Resource not found"); // Update the C# file. - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), "//v2\n" + s_programReadingEmbeddedResource); + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), "//v2\n" + code); - Build(testInstance, BuildLevel.Csc, expectedOutput: "[MyString, TestValue]"); // note: outdated output (only CSC used) + Build(testInstance, optOut ? BuildLevel.All : BuildLevel.Csc, expectedOutput: optOut ? "[MyString, UpdatedValue]" : "Resource not found"); + + Build(testInstance, BuildLevel.All, ["--no-cache"], expectedOutput: "[MyString, UpdatedValue]"); + + // Update the C# file. + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), "//v3\n" + code); + + Build(testInstance, optOut ? BuildLevel.All : BuildLevel.Csc, expectedOutput: "[MyString, UpdatedValue]"); + } + + /// + /// Combination of with optimization. + /// + [Theory, CombinatorialData] // https://github.com/dotnet/sdk/issues/50912 + public void UpToDate_DefaultItems_CscOnly_AfterMSBuild(bool optOut) + { + var testInstance = _testAssetsManager.CreateTestDirectory(baseDirectory: OutOfTreeBaseDirectory); + var code = $""" + #:property Configuration=Release + {(optOut ? "#:property FileBasedProgramCanSkipMSBuild=false" : "")} + {s_programReadingEmbeddedResource} + """; + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), code); + File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx); + + Build(testInstance, BuildLevel.All, expectedOutput: "[MyString, TestValue]"); + + // Update the C# file. + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), "//v2\n" + code); + + Build(testInstance, optOut ? BuildLevel.All : BuildLevel.Csc, expectedOutput: optOut ? "[MyString, TestValue]" : "[MyString, TestValue]"); + + // Update the RESX file. + File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx.Replace("TestValue", "UpdatedValue")); + + Build(testInstance, optOut ? BuildLevel.All : BuildLevel.None, expectedOutput: optOut ? "[MyString, UpdatedValue]" : "[MyString, TestValue]"); + + // Update the C# file. + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), "//v3\n" + code); + + Build(testInstance, optOut ? BuildLevel.All : BuildLevel.Csc, expectedOutput: optOut ? "[MyString, UpdatedValue]" : "[MyString, TestValue]"); Build(testInstance, BuildLevel.All, ["--no-cache"], expectedOutput: "[MyString, UpdatedValue]"); } @@ -3034,6 +3235,27 @@ public void CscOnly_SpacesInPath() Build(testInstance, BuildLevel.Csc, expectedOutput: "v1", programFileName: programFileName); } + [Fact] // https://github.com/dotnet/sdk/issues/50778 + public void CscOnly_Args() + { + var testInstance = _testAssetsManager.CreateTestDirectory(baseDirectory: OutOfTreeBaseDirectory); + var programPath = Path.Join(testInstance.Path, "Program.cs"); + File.WriteAllText(programPath, s_program); + + // Remove artifacts from possible previous runs of this test. + var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programPath); + if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true); + + Build(testInstance, BuildLevel.Csc, args: ["test", "args"], expectedOutput: """ + echo args:test;args + Hello from Program + """); + } + + /// + /// Tests an optimization which remembers CSC args from prior MSBuild runs and can skip subsequent MSBuild invocations and call CSC directly. + /// This optimization kicks in when the file has some #: directives (then the simpler "hard-coded CSC args" optimization cannot be used). + /// [Fact] public void CscOnly_AfterMSBuild() { @@ -3089,6 +3311,9 @@ public void CscOnly_AfterMSBuild() Build(testInstance, BuildLevel.All, expectedOutput: "v4 "); } + /// + /// See . + /// [Fact] public void CscOnly_AfterMSBuild_SpacesInPath() { @@ -3119,6 +3344,46 @@ public void CscOnly_AfterMSBuild_SpacesInPath() Build(testInstance, BuildLevel.Csc, expectedOutput: "v2 Release", programFileName: programFileName); } + /// + /// See . + /// + [Fact] + public void CscOnly_AfterMSBuild_Args() + { + var testInstance = _testAssetsManager.CreateTestDirectory(baseDirectory: OutOfTreeBaseDirectory); + var programPath = Path.Join(testInstance.Path, "Program.cs"); + + var code = $""" + #:property Configuration=Release + {s_program} + """; + + File.WriteAllText(programPath, code); + + // Remove artifacts from possible previous runs of this test. + var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programPath); + if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true); + + Build(testInstance, BuildLevel.All, args: ["test", "args"], expectedOutput: """ + echo args:test;args + Hello from Program + Release config + """); + + code = code.Replace("Hello", "Hi"); + File.WriteAllText(programPath, code); + + Build(testInstance, BuildLevel.Csc, ["test", "args"], expectedOutput: """ + echo args:test;args + Hi from Program + Release config + """); + } + + /// + /// See . + /// This optimization currently does not support #:project references and hence is disabled if those are present. + /// [Fact] public void CscOnly_AfterMSBuild_ProjectReferences() { @@ -3175,8 +3440,8 @@ public class LibClass } /// - /// If users have more complex build customizations, they can opt out of the optimization which - /// reuses CSC arguments and skips subsequent MSBuild invocations. + /// See . + /// If users have more complex build customizations, they can opt out of the optimization. /// [Theory, CombinatorialData] public void CscOnly_AfterMSBuild_OptOut(bool canSkipMSBuild, bool inDirectoryBuildProps) @@ -3220,6 +3485,9 @@ public void CscOnly_AfterMSBuild_OptOut(bool canSkipMSBuild, bool inDirectoryBui Build(testInstance, canSkipMSBuild ? BuildLevel.Csc : BuildLevel.All, expectedOutput: "v2 Release"); } + /// + /// See . + /// [Fact] public void CscOnly_AfterMSBuild_AuxiliaryFilesNotReused() { @@ -3295,6 +3563,14 @@ public void Api() artifacts/$(MSBuildProjectName) artifacts/$(MSBuildProjectName) true + false + true + Exe + {ToolsetInfo.CurrentTargetFramework} + enable + enable + true + true @@ -3305,15 +3581,9 @@ public void Api() - Exe - enable - enable - true - false - true - false net11.0 preview + false $(Features);FileBasedProgram @@ -3365,6 +3635,14 @@ public void Api_Diagnostic_01() artifacts/$(MSBuildProjectName) artifacts/$(MSBuildProjectName) true + false + true + Exe + {ToolsetInfo.CurrentTargetFramework} + enable + enable + true + true @@ -3374,13 +3652,6 @@ public void Api_Diagnostic_01() - Exe - {ToolsetInfo.CurrentTargetFramework} - enable - enable - true - false - true false $(Features);FileBasedProgram @@ -3432,6 +3703,14 @@ public void Api_Diagnostic_02() artifacts/$(MSBuildProjectName) artifacts/$(MSBuildProjectName) true + false + true + Exe + {ToolsetInfo.CurrentTargetFramework} + enable + enable + true + true @@ -3441,13 +3720,6 @@ public void Api_Diagnostic_02() - Exe - {ToolsetInfo.CurrentTargetFramework} - enable - enable - true - false - true false $(Features);FileBasedProgram diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs b/src/sdk/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs index 8ced55de734..08d323f2cc2 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs @@ -146,9 +146,9 @@ public void TrackRunEvent_FileBasedApp_SendsCorrectTelemetry() { // Arrange var events = new List<(string? eventName, IDictionary? properties, IDictionary? measurements)>(); - + void handler(object? sender, InstrumentationEventArgs args) => events.Add((args.EventName, args.Properties, args.Measurements)); - + TelemetryEventEntry.EntryPosted += handler; try @@ -172,18 +172,21 @@ public void TrackRunEvent_FileBasedApp_SendsCorrectTelemetry() var eventData = events[0]; eventData.eventName.Should().Be("run"); eventData.properties.Should().NotBeNull(); - + eventData.measurements.Should().NotBeNull(); + var props = eventData.properties!; props["app_type"].Should().Be("file_based"); props["project_id"].Should().Be("test-hash"); - props["sdk_count"].Should().Be("2"); - props["package_reference_count"].Should().Be("3"); - props["project_reference_count"].Should().Be("1"); - props["additional_properties_count"].Should().Be("2"); props["used_msbuild"].Should().Be("true"); props["used_roslyn_compiler"].Should().Be("false"); props["launch_profile_requested"].Should().Be("explicit"); props["launch_profile_is_default"].Should().Be("true"); + + var measurements = eventData.measurements!; + measurements["sdk_count"].Should().Be(2); + measurements["package_reference_count"].Should().Be(3); + measurements["project_reference_count"].Should().Be(1); + measurements["additional_properties_count"].Should().Be(2); } finally { @@ -197,9 +200,9 @@ public void TrackRunEvent_ProjectBasedApp_SendsCorrectTelemetry() { // Arrange var events = new List<(string? eventName, IDictionary? properties, IDictionary? measurements)>(); - + void handler(object? sender, InstrumentationEventArgs args) => events.Add((args.EventName, args.Properties, args.Measurements)); - + TelemetryEventEntry.EntryPosted += handler; try @@ -220,17 +223,20 @@ public void TrackRunEvent_ProjectBasedApp_SendsCorrectTelemetry() var eventData = events[0]; eventData.eventName.Should().Be("run"); eventData.properties.Should().NotBeNull(); - + eventData.measurements.Should().NotBeNull(); + var props = eventData.properties!; props["app_type"].Should().Be("project_based"); props["project_id"].Should().Be("project-hash"); - props["sdk_count"].Should().Be("1"); - props["package_reference_count"].Should().Be("5"); - props["project_reference_count"].Should().Be("2"); props["launch_profile_requested"].Should().Be("none"); - props.Should().NotContainKey("additional_properties_count"); props.Should().NotContainKey("used_msbuild"); props.Should().NotContainKey("used_roslyn_compiler"); + + var measurements = eventData.measurements!; + measurements["sdk_count"].Should().Be(1); + measurements["package_reference_count"].Should().Be(5); + measurements["project_reference_count"].Should().Be(2); + measurements.Should().NotContainKey("additional_properties_count"); } finally { @@ -244,9 +250,9 @@ public void TrackRunEvent_WithDefaultLaunchProfile_MarksTelemetryCorrectly() { // Arrange var events = new List<(string? eventName, IDictionary? properties, IDictionary? measurements)>(); - + void handler(object? sender, InstrumentationEventArgs args) => events.Add((args.EventName, args.Properties, args.Measurements)); - + TelemetryEventEntry.EntryPosted += handler; var launchSettings = new ProjectLaunchSettingsModel diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestfromCsproj.cs b/src/sdk/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestfromCsproj.cs index 85d6749e07a..96b0e9edb73 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestfromCsproj.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestfromCsproj.cs @@ -804,6 +804,38 @@ public void ArgumentsEndWithDllOrExeShouldNotFail(string arg) } } + + [Theory] + [InlineData("-p:ABC=C:\\my.dll")] + [InlineData("/p:ABC=C:\\my.dll")] + [InlineData("-property:ABC=C:\\my.dll")] + public void PropertiesEndingWithDotDllShouldNotFail(string property) + { + var testProjectDirectory = CopyAndRestoreVSTestDotNetCoreTestApp([]); + + // Call test + // The test will complain about --property:VsTestUseMSBuildOutput=false but + // it is the .dll parameter that is causing this. It forces the command to offload work + // to vstest.console.exe directly, because it thinks there is some test .dll that we should run + // directly, rather than a project file. + // Vstest.console.exe will then complain just about the first unknown parameter. + CommandResult result = new DotnetTestCommand(Log, disableNewOutput: true) + .WithWorkingDirectory(testProjectDirectory) + .Execute(ConsoleLoggerOutputNormal.Concat([property])); + + // Verify + if (!TestContext.IsLocalized()) + { + result.StdOut.Should().Contain("Total tests: 2"); + result.StdOut.Should().Contain("Passed: 1"); + result.StdOut.Should().Contain("Failed: 1"); + result.StdOut.Should().Contain("Passed VSTestPassTest"); + result.StdOut.Should().Contain("Failed VSTestFailTest"); + } + + result.ExitCode.Should().Be(1); + } + private string CopyAndRestoreVSTestDotNetCoreTestApp(object[] parameters, [CallerMemberName] string callingMethod = "") { // Copy VSTestCore project in output directory of project dotnet-vstest.Tests diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Tool/Install/ToolInstallGlobalOrToolPathCommandTests.cs b/src/sdk/test/dotnet.Tests/CommandTests/Tool/Install/ToolInstallGlobalOrToolPathCommandTests.cs index ea127f2fbba..0d80b9d9d13 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/Tool/Install/ToolInstallGlobalOrToolPathCommandTests.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/Tool/Install/ToolInstallGlobalOrToolPathCommandTests.cs @@ -197,7 +197,7 @@ public void WhenRunWithSourceItShouldFindOnlyTheProvidedSource() [Fact] public void WhenRunWithPackageIdWithSourceItShouldCreateValidShim() { - const string sourcePath = "http://mysource.com"; + const string sourcePath = "https://mysource.com"; ParseResult result = Parser.Parse($"dotnet tool install -g {PackageId} --add-source {sourcePath}"); var toolInstallGlobalOrToolPathCommand = new ToolInstallGlobalOrToolPathCommand( @@ -666,7 +666,6 @@ public void WhenRunWithoutValidVersionUnlistedToolItShouldThrow() var testDir = _testAssetsManager.CreateTestDirectory().Path; var toolInstallGlobalOrToolPathCommand = new DotnetCommand(Log, "tool", "install", "-g", UnlistedPackageId, "--add-source", nugetSourcePath) - .WithEnvironmentVariable("DOTNET_SKIP_WORKLOAD_INTEGRITY_CHECK", "true") .WithWorkingDirectory(testDir); toolInstallGlobalOrToolPathCommand.Execute().Should().Fail(); @@ -928,6 +927,78 @@ public void WhenRunWithArchOptionItDownloadsAppHostTemplate() nugetPackageDownloader.DownloadCallParams.First().Item1.Should().Be(new PackageId("microsoft.netcore.app.host.win-arm64")); } + [Fact] + public void WhenRunWithHttpSourceViaAddSourceItShouldShowNU1302Error() + { + var testDir = _testAssetsManager.CreateTestDirectory().Path; + + var toolInstallCommand = new DotnetCommand(Log, "tool", "install", "-g", "fake-tool", "--add-source", "http://test.example.com/nuget") + .WithWorkingDirectory(testDir); + + var result = toolInstallCommand.Execute(); + + result.Should().Fail(); + result.StdErr.Should().Contain("You are running the 'tool install' operation with an 'HTTP' source: http://test.example.com/nuget"); + result.StdErr.Should().Contain("NuGet requires HTTPS sources"); + result.StdErr.Should().Contain("allowInsecureConnections"); + } + + [Fact] + public void WhenRunWithHttpSourceInNuGetConfigItShouldShowNU1302Error() + { + var testDir = _testAssetsManager.CreateTestDirectory().Path; + var nugetConfigPath = Path.Combine(testDir, "nuget.config"); + + var nugetConfigContent = @" + + + + + +"; + + File.WriteAllText(nugetConfigPath, nugetConfigContent); + + var toolInstallCommand = new DotnetCommand(Log, "tool", "install", "-g", "fake-tool") + .WithWorkingDirectory(testDir); + + var result = toolInstallCommand.Execute(); + + result.Should().Fail(); + result.StdErr.Should().Contain("You are running the 'tool install' operation with an 'HTTP' source: http://test.example.com/nuget"); + result.StdErr.Should().Contain("NuGet requires HTTPS sources"); + result.StdErr.Should().Contain("allowInsecureConnections"); + } + + [Fact] + public void WhenRunWithHttpSourceAndAllowInsecureConnectionsItShouldSucceed() + { + var testDir = _testAssetsManager.CreateTestDirectory().Path; + var nugetConfigPath = Path.Combine(testDir, "nuget.config"); + + var nugetConfigContent = @" + + + + + +"; + + File.WriteAllText(nugetConfigPath, nugetConfigContent); + + var toolInstallCommand = new DotnetCommand(Log, "tool", "install", "-g", "fake-tool") + .WithWorkingDirectory(testDir); + + var result = toolInstallCommand.Execute(); + + // Should fail for other reasons (unable to load service index) but not due to HTTP source validation + result.Should().Fail(); + result.StdErr.Should().NotContain("You are running the 'tool install' operation with an 'HTTP' source:"); + result.StdErr.Should().NotContain("NuGet requires HTTPS sources"); + // Should fail because the service index can't be loaded, not because of HTTP validation + result.StdErr.Should().Contain("Unable to load the service index"); + } + private string ExpectedCommandPath() { var extension = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : string.Empty; diff --git a/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh b/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh index 0e1338dd888..c6b13b33237 100644 --- a/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh +++ b/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh @@ -1137,7 +1137,7 @@ _testhost_package_update() { prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=() - opts="--project --interactive --verbosity --help" + opts="--project --vulnerable --interactive --verbosity --help" if [[ $COMP_CWORD == "$1" ]]; then COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) @@ -1145,6 +1145,10 @@ _testhost_package_update() { fi case $prev in + --vulnerable) + COMPREPLY=( $(compgen -W "False True" -- "$cur") ) + return + ;; --interactive) COMPREPLY=( $(compgen -W "False True" -- "$cur") ) return diff --git a/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 index e112a825b4a..7a9a85fb4e4 100644 --- a/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 +++ b/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 @@ -48,7 +48,7 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { [CompletionResult]::new('solution', 'solution', [CompletionResultType]::ParameterValue, ".NET modify solution file command") [CompletionResult]::new('solution', 'sln', [CompletionResultType]::ParameterValue, ".NET modify solution file command") [CompletionResult]::new('store', 'store', [CompletionResultType]::ParameterValue, "Stores the specified assemblies for the .NET Platform. By default, these will be optimized for the target runtime and framework.") - [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, ".NET Test Driver") + [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, ".NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test.") [CompletionResult]::new('tool', 'tool', [CompletionResultType]::ParameterValue, "Install or work with tools that extend the .NET experience.") [CompletionResult]::new('vstest', 'vstest', [CompletionResultType]::ParameterValue, "vstest") [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, ".NET CLI help utility") @@ -671,6 +671,7 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { 'testhost;package;update' { $staticCompletions = @( [CompletionResult]::new('--project', '--project', [CompletionResultType]::ParameterName, "Path to a project or solution file, or a directory.") + [CompletionResult]::new('--vulnerable', '--vulnerable', [CompletionResultType]::ParameterName, "Upgrade packages with known vulnerabilities.") [CompletionResult]::new('--interactive', '--interactive', [CompletionResultType]::ParameterName, "Allows the command to stop and wait for user input or action (for example to complete authentication).") [CompletionResult]::new('--verbosity', '--verbosity', [CompletionResultType]::ParameterName, "Set the verbosity level of the command. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") [CompletionResult]::new('--verbosity', '-v', [CompletionResultType]::ParameterName, "Set the verbosity level of the command. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") diff --git a/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh index 03a8a7c0f29..0718ee370c8 100644 --- a/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh +++ b/src/sdk/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh @@ -669,6 +669,7 @@ _testhost() { (update) _arguments "${_arguments_options[@]}" : \ '--project=[Path to a project or solution file, or a directory.]: : ' \ + '--vulnerable=[Upgrade packages with known vulnerabilities.]: :((False\:"False" True\:"True" ))' \ '--interactive=[Allows the command to stop and wait for user input or action (for example to complete authentication).]: :((False\:"False" True\:"True" ))' \ '--verbosity=[Set the verbosity level of the command. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]: :((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ '-v=[Set the verbosity level of the command. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]: :((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ @@ -1102,7 +1103,7 @@ _testhost() { '--allow-roll-forward[Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn'\''t installed.]' \ '--help[Show command line help.]' \ '-h[Show command line help.]' \ - ':packageId -- Package reference in the form of a package identifier like '\''Newtonsoft.Json'\'' or package identifier and version separated by '\''@'\'' like '\''Newtonsoft.Json@13.0.3'\''.:->dotnet_dynamic_complete' \ + ':packageId -- Package reference in the form of a package identifier like '\''dotnetsay'\'' or package identifier and version separated by '\''@'\'' like '\''dotnetsay@2.1.7'\''.:->dotnet_dynamic_complete' \ && ret=0 case $state in (dotnet_dynamic_complete) @@ -1150,7 +1151,7 @@ _testhost() { '--all[Update all tools.]' \ '--help[Show command line help.]' \ '-h[Show command line help.]' \ - '::packageId -- Package reference in the form of a package identifier like '\''Newtonsoft.Json'\'' or package identifier and version separated by '\''@'\'' like '\''Newtonsoft.Json@13.0.3'\''.:->dotnet_dynamic_complete' \ + '::packageId -- Package reference in the form of a package identifier like '\''dotnetsay'\'' or package identifier and version separated by '\''@'\'' like '\''dotnetsay@2.1.7'\''.:->dotnet_dynamic_complete' \ && ret=0 case $state in (dotnet_dynamic_complete) @@ -1228,7 +1229,7 @@ _testhost() { '-v=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ '--help[Show command line help.]' \ '-h[Show command line help.]' \ - ':packageId -- Package reference in the form of a package identifier like '\''Newtonsoft.Json'\'' or package identifier and version separated by '\''@'\'' like '\''Newtonsoft.Json@13.0.3'\''.:->dotnet_dynamic_complete' \ + ':packageId -- Package reference in the form of a package identifier like '\''dotnetsay'\'' or package identifier and version separated by '\''@'\'' like '\''dotnetsay@2.1.7'\''.:->dotnet_dynamic_complete' \ '*::commandArguments -- Arguments forwarded to the tool: ' \ && ret=0 case $state in @@ -1493,7 +1494,7 @@ _testhost_commands() { 'run:.NET Run Command' \ 'solution:.NET modify solution file command' \ 'store:Stores the specified assemblies for the .NET Platform. By default, these will be optimized for the target runtime and framework.' \ - 'test:.NET Test Driver' \ + 'test:.NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https\://aka.ms/dotnet-test.' \ 'tool:Install or work with tools that extend the .NET experience.' \ 'vstest:' \ 'help:.NET CLI help utility' \ diff --git a/src/sdk/test/dotnet.Tests/TelemetryCommonPropertiesTests.cs b/src/sdk/test/dotnet.Tests/TelemetryCommonPropertiesTests.cs index a77f0bf8176..4e28b92479d 100644 --- a/src/sdk/test/dotnet.Tests/TelemetryCommonPropertiesTests.cs +++ b/src/sdk/test/dotnet.Tests/TelemetryCommonPropertiesTests.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - using Microsoft.DotNet.Cli.Telemetry; using Microsoft.DotNet.Configurer; @@ -193,29 +191,34 @@ public void CanDetectCIStatusForEnvVars(Dictionary envVars, bool [Theory] [MemberData(nameof(LLMTelemetryTestCases))] - public void CanDetectLLMStatusForEnvVars(Dictionary envVars, string expected) + public void CanDetectLLMStatusForEnvVars(Dictionary? envVars, string? expected) { try { - foreach (var (key, value) in envVars) - { - Environment.SetEnvironmentVariable(key, value); + if (envVars is not null){ + foreach (var (key, value) in envVars) + { + Environment.SetEnvironmentVariable(key, value); + } } new LLMEnvironmentDetectorForTelemetry().GetLLMEnvironment().Should().Be(expected); } finally { - foreach (var (key, value) in envVars) + if (envVars is not null) { - Environment.SetEnvironmentVariable(key, null); + foreach (var (key, value) in envVars) + { + Environment.SetEnvironmentVariable(key, null); + } } } } - + [Theory] [InlineData("dummySessionId")] [InlineData(null)] - public void TelemetryCommonPropertiesShouldContainSessionId(string sessionId) + public void TelemetryCommonPropertiesShouldContainSessionId(string? sessionId) { var unitUnderTest = new TelemetryCommonProperties(userLevelCacheWriter: new NothingCache()); var commonProperties = unitUnderTest.GetTelemetryCommonProperties(sessionId); @@ -225,34 +228,42 @@ public void TelemetryCommonPropertiesShouldContainSessionId(string sessionId) } - public static IEnumerable LLMTelemetryTestCases => new List{ - new object[] { new Dictionary { { "CLAUDECODE", "1" } }, "claude" }, - new object[] { new Dictionary { { "CURSOR_EDITOR", "1" } }, "cursor" }, - new object[] { new Dictionary { { "CLAUDECODE", "1" }, { "CURSOR_EDITOR", "1" } }, "claude, cursor" }, - new object[] { new Dictionary(), null }, + public static TheoryData?, string?> LLMTelemetryTestCases => new() + { + { new Dictionary { {"CLAUDECODE", "1" } }, "claude" }, + { new Dictionary { { "CURSOR_EDITOR", "1" } }, "cursor" }, + { new Dictionary { { "GEMINI_CLI", "true" } }, "gemini" }, + { new Dictionary { { "GITHUB_COPILOT_CLI_MODE", "true" } }, "copilot" }, + { new Dictionary { { "AGENT_CLI", "true" } }, "generic_agent" }, + { new Dictionary { { "CLAUDECODE", "1" }, { "CURSOR_EDITOR", "1" } }, "claude, cursor" }, + { new Dictionary { { "GEMINI_CLI", "true" }, { "GITHUB_COPILOT_CLI_MODE", "true" } }, "gemini, copilot" }, + { new Dictionary { { "CLAUDECODE", "1" }, { "GEMINI_CLI", "true" }, { "AGENT_CLI", "true" } }, "claude, gemini, generic_agent" }, + { new Dictionary { { "CLAUDECODE", "1" }, { "CURSOR_EDITOR", "1" }, { "GEMINI_CLI", "true" }, { "GITHUB_COPILOT_CLI_MODE", "true" }, { "AGENT_CLI", "true" } }, "claude, cursor, gemini, copilot, generic_agent" }, + { new Dictionary { { "GEMINI_CLI", "false" } }, null }, + { new Dictionary { { "GITHUB_COPILOT_CLI_MODE", "false" } }, null }, + { new Dictionary { { "AGENT_CLI", "false" } }, null }, + { new Dictionary(), null }, }; - public static IEnumerable CITelemetryTestCases => new List{ - new object[] { new Dictionary { { "TF_BUILD", "true" } }, true }, - new object[] { new Dictionary { { "GITHUB_ACTIONS", "true" } }, true }, - new object[] { new Dictionary { { "APPVEYOR", "true"} }, true }, - new object[] { new Dictionary { { "CI", "true"} }, true }, - new object[] { new Dictionary { { "TRAVIS", "true"} }, true }, - new object[] { new Dictionary { { "CIRCLECI", "true"} }, true }, - - new object[] { new Dictionary { { "CODEBUILD_BUILD_ID", "hi" }, { "AWS_REGION", "hi" } }, true }, - new object[] { new Dictionary { { "CODEBUILD_BUILD_ID", "hi" } }, false }, - new object[] { new Dictionary { { "BUILD_ID", "hi" }, { "BUILD_URL", "hi" } }, true }, - new object[] { new Dictionary { { "BUILD_ID", "hi" } }, false }, - new object[] { new Dictionary { { "BUILD_ID", "hi" }, { "PROJECT_ID", "hi" } }, true }, - new object[] { new Dictionary { { "BUILD_ID", "hi" } }, false }, - - new object[] { new Dictionary { { "TEAMCITY_VERSION", "hi" } }, true }, - new object[] { new Dictionary { { "TEAMCITY_VERSION", "" } }, false }, - new object[] { new Dictionary { { "JB_SPACE_API_URL", "hi" } }, true }, - new object[] { new Dictionary { { "JB_SPACE_API_URL", "" } }, false }, - - new object[] { new Dictionary { { "SomethingElse", "hi" } }, false }, + public static TheoryData, bool> CITelemetryTestCases => new() + { + { new Dictionary { { "TF_BUILD", "true" } }, true }, + { new Dictionary { { "GITHUB_ACTIONS", "true" } }, true }, + { new Dictionary { { "APPVEYOR", "true"} }, true }, + { new Dictionary { { "CI", "true"} }, true }, + { new Dictionary { { "TRAVIS", "true"} }, true }, + { new Dictionary { { "CIRCLECI", "true"} }, true }, +{ new Dictionary { { "CODEBUILD_BUILD_ID", "hi" }, { "AWS_REGION", "hi" } }, true }, + { new Dictionary { { "CODEBUILD_BUILD_ID", "hi" } }, false }, + { new Dictionary { { "BUILD_ID", "hi" }, { "BUILD_URL", "hi" } }, true }, + { new Dictionary { { "BUILD_ID", "hi" } }, false }, + { new Dictionary { { "BUILD_ID", "hi" }, { "PROJECT_ID", "hi" } }, true }, + { new Dictionary { { "BUILD_ID", "hi" } }, false }, +{ new Dictionary { { "TEAMCITY_VERSION", "hi" } }, true }, + { new Dictionary { { "TEAMCITY_VERSION", "" } }, false }, + { new Dictionary { { "JB_SPACE_API_URL", "hi" } }, true }, + { new Dictionary { { "JB_SPACE_API_URL", "" } }, false }, +{ new Dictionary { { "SomethingElse", "hi" } }, false }, }; private class NothingCache : IUserLevelCacheWriter diff --git a/src/source-manifest.json b/src/source-manifest.json index d93558e1c66..ddb7d14b617 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -91,10 +91,10 @@ "commitSha": "082359066ee0064039b9b1f1f025bdd0507d06de" }, { - "barId": 284072, + "barId": 286006, "path": "sdk", "remoteUri": "https://github.com/dotnet/sdk", - "commitSha": "b7b9812866f245761b3af8d526bede699e170efc" + "commitSha": "cf932ba08b38f8a148536f5d0e9c98d56280cc24" }, { "barId": 282656, diff --git a/test/Microsoft.DotNet.SourceBuild.Tests/DotNetWatchTests.cs b/test/Microsoft.DotNet.SourceBuild.Tests/DotNetWatchTests.cs index cf97c63813d..87c52189086 100644 --- a/test/Microsoft.DotNet.SourceBuild.Tests/DotNetWatchTests.cs +++ b/test/Microsoft.DotNet.SourceBuild.Tests/DotNetWatchTests.cs @@ -40,7 +40,7 @@ void processConfigCallback(Process process) bool fileChanged = false; - process.OutputDataReceived += new DataReceivedEventHandler((sender, e) => + process.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => { if (e.Data == null) { @@ -51,11 +51,11 @@ void processConfigCallback(Process process) { OutputHelper.WriteLine(e.Data); } - catch + catch { // avoid System.InvalidOperationException: There is no currently active test. } - + if (e.Data.Contains(waitingString)) { if (!fileChanged) { @@ -66,7 +66,25 @@ void processConfigCallback(Process process) fileChanged = true; } } - else if (e.Data.Contains(expectedString)) + }); + + process.OutputDataReceived += new DataReceivedEventHandler((sender, e) => + { + if (e.Data == null) + { + return; + } + + try + { + OutputHelper.WriteLine(e.Data); + } + catch + { + // avoid System.InvalidOperationException: There is no currently active test. + } + + if (e.Data.Contains(expectedString)) { outputChanged = true; OutputHelper.WriteLine("Successfully re-ran program after code change."); From 5635bae27dce8e3358a2117b544f3b99805f5bbd Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:15:58 +0000 Subject: [PATCH 03/28] [release/10.0.1xx] Source code updates from dotnet/razor (#2781) [release/10.0.1xx] Source code updates from dotnet/razor --- src/razor/eng/Version.Details.xml | 2 +- src/razor/eng/config/PublishData.json | 88 +------------ .../Cohost/SemanticTokensRefreshNotifier.cs | 56 --------- .../LanguageClient/Options/OptionsStorage.cs | 117 ++++++++++++++---- .../LanguageClient/Options/SettingsNames.cs | 25 ++-- src/source-manifest.json | 4 +- 6 files changed, 113 insertions(+), 179 deletions(-) delete mode 100644 src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/SemanticTokensRefreshNotifier.cs diff --git a/src/razor/eng/Version.Details.xml b/src/razor/eng/Version.Details.xml index 9faa47fefeb..f760cc8a904 100644 --- a/src/razor/eng/Version.Details.xml +++ b/src/razor/eng/Version.Details.xml @@ -1,6 +1,6 @@ - + https://github.com/dotnet/roslyn diff --git a/src/razor/eng/config/PublishData.json b/src/razor/eng/config/PublishData.json index 6a982ed7075..84dbf02c6af 100644 --- a/src/razor/eng/config/PublishData.json +++ b/src/razor/eng/config/PublishData.json @@ -22,92 +22,6 @@ } }, "branches": { - "main": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "main", - "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[dNext]" - }, - "release/dev17.6": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.6", - "insertionTitlePrefix": "[17.6]" - }, - "release/dev17.7": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.7", - "insertionTitlePrefix": "[17.7]" - }, - "release/dev17.8": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.8", - "insertionTitlePrefix": "[17.8]" - }, - "release/dev17.9": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.9", - "insertionTitlePrefix": "[17.9]" - }, - "release/dev17.10": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.10", - "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[17.10]" - }, - "release/dev17.11": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.11", - "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[17.11]" - }, - "release/dev17.12": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.12", - "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d17.12]" - }, - "release/dev17.13": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.13", - "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d17.13]" - }, - "release/dev17.14": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.14", - "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d17.14 P3]" - }, "release/dev18.0": { "nugetKind": [ "Shipping", @@ -115,7 +29,7 @@ ], "vsBranch": "rel/d18.0", "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d18.0]" + "insertionTitlePrefix": "[d18.0 Insiders]" } } } diff --git a/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/SemanticTokensRefreshNotifier.cs b/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/SemanticTokensRefreshNotifier.cs deleted file mode 100644 index 20cb0794c44..00000000000 --- a/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/SemanticTokensRefreshNotifier.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.ComponentModel.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.ExternalAccess.Razor; -using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; -using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; -using Microsoft.VisualStudio.Razor.LanguageClient.Cohost; -using Microsoft.VisualStudio.Threading; - -namespace Microsoft.AspNetCore.Razor.LanguageServer; - -[Export(typeof(IRazorCohostStartupService))] -[method: ImportingConstructor] -internal sealed class SemanticTokensRefreshNotifier(IClientSettingsManager clientSettingsManager) : IRazorCohostStartupService, IDisposable -{ - private readonly IClientSettingsManager _clientSettingsManager = clientSettingsManager; - - private IRazorClientLanguageServerManager? _razorClientLanguageServerManager; - private bool _lastColorBackground; - - public int Order => WellKnownStartupOrder.Default; - - public Task StartupAsync(VSInternalClientCapabilities clientCapabilities, RazorCohostRequestContext requestContext, CancellationToken cancellationToken) - { - _razorClientLanguageServerManager = requestContext.GetRequiredService(); - - if (clientCapabilities.Workspace?.SemanticTokens?.RefreshSupport ?? false) - { - _lastColorBackground = _clientSettingsManager.GetClientSettings().AdvancedSettings.ColorBackground; - _clientSettingsManager.ClientSettingsChanged += ClientSettingsManager_ClientSettingsChanged; - } - - return Task.CompletedTask; - } - - private void ClientSettingsManager_ClientSettingsChanged(object sender, EventArgs e) - { - var colorBackground = _clientSettingsManager.GetClientSettings().AdvancedSettings.ColorBackground; - if (colorBackground == _lastColorBackground) - { - return; - } - - _lastColorBackground = colorBackground; - _razorClientLanguageServerManager.AssumeNotNull().SendNotificationAsync(Methods.WorkspaceSemanticTokensRefreshName, CancellationToken.None).Forget(); - } - - public void Dispose() - { - _clientSettingsManager.ClientSettingsChanged -= ClientSettingsManager_ClientSettingsChanged; - } -} diff --git a/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/OptionsStorage.cs b/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/OptionsStorage.cs index 01db1266b91..c6c8570685a 100644 --- a/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/OptionsStorage.cs +++ b/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/OptionsStorage.cs @@ -2,18 +2,21 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel.Composition; +using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.CodeAnalysis.Razor.Telemetry; using Microsoft.Internal.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Razor.Settings; +using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell.Settings; using Microsoft.VisualStudio.Threading; using Microsoft.VisualStudio.Utilities.UnifiedSettings; @@ -23,12 +26,73 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.Options; [Export(typeof(IAdvancedSettingsStorage))] internal class OptionsStorage : IAdvancedSettingsStorage, IDisposable { + private readonly WritableSettingsStore _writableSettingsStore; + private readonly Lazy _telemetryReporter; private readonly JoinableTask _initializeTask; private ImmutableArray _taskListDescriptors = []; private ISettingsReader? _unifiedSettingsReader; private IDisposable? _unifiedSettingsSubscription; private bool _changedBeforeSubscription; + public bool FormatOnType + { + get => GetBool(SettingsNames.FormatOnType.LegacyName, defaultValue: true); + set => SetBool(SettingsNames.FormatOnType.LegacyName, value); + } + + public bool AutoClosingTags + { + get => GetBool(SettingsNames.AutoClosingTags.LegacyName, defaultValue: true); + set => SetBool(SettingsNames.AutoClosingTags.LegacyName, value); + } + + public bool AutoInsertAttributeQuotes + { + get => GetBool(SettingsNames.AutoInsertAttributeQuotes.LegacyName, defaultValue: true); + set => SetBool(SettingsNames.AutoInsertAttributeQuotes.LegacyName, value); + } + + public bool ColorBackground + { + get => GetBool(SettingsNames.ColorBackground.LegacyName, defaultValue: false); + set => SetBool(SettingsNames.ColorBackground.LegacyName, value); + } + + public bool CodeBlockBraceOnNextLine + { + get => GetBool(SettingsNames.CodeBlockBraceOnNextLine.LegacyName, defaultValue: false); + set => SetBool(SettingsNames.CodeBlockBraceOnNextLine.LegacyName, value); + } + + public bool CommitElementsWithSpace + { + get => GetBool(SettingsNames.CommitElementsWithSpace.LegacyName, defaultValue: true); + set => SetBool(SettingsNames.CommitElementsWithSpace.LegacyName, value); + } + + public SnippetSetting Snippets + { + get => (SnippetSetting)GetInt(SettingsNames.Snippets.LegacyName, (int)SnippetSetting.All); + set => SetInt(SettingsNames.Snippets.LegacyName, (int)value); + } + + public LogLevel LogLevel + { + get => (LogLevel)GetInt(SettingsNames.LogLevel.LegacyName, (int)LogLevel.Warning); + set => SetInt(SettingsNames.LogLevel.LegacyName, (int)value); + } + + public bool FormatOnPaste + { + get => GetBool(SettingsNames.FormatOnPaste.LegacyName, defaultValue: true); + set => SetBool(SettingsNames.FormatOnPaste.LegacyName, value); + } + + public ImmutableArray TaskListDescriptors + { + get { return _taskListDescriptors; } + } + [ImportingConstructor] public OptionsStorage( SVsServiceProvider synchronousServiceProvider, @@ -36,11 +100,17 @@ public OptionsStorage( Lazy telemetryReporter, JoinableTaskContext joinableTaskContext) { + var shellSettingsManager = new ShellSettingsManager(synchronousServiceProvider); + _writableSettingsStore = shellSettingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); + + _writableSettingsStore.CreateCollection(SettingsNames.LegacyCollection); + _telemetryReporter = telemetryReporter; + _initializeTask = joinableTaskContext.Factory.RunAsync(async () => { - var unifiedSettingsManager = await serviceProvider.GetServiceAsync(); + var unifiedSettingsManager = await serviceProvider.GetServiceAsync(); _unifiedSettingsReader = unifiedSettingsManager.GetReader(); - _unifiedSettingsSubscription = _unifiedSettingsReader.SubscribeToChanges(OnUnifiedSettingsChanged, SettingsNames.AllSettings); + _unifiedSettingsSubscription = _unifiedSettingsReader.SubscribeToChanges(OnUnifiedSettingsChanged, SettingsNames.AllSettings.Select(s => s.UnifiedName).ToArray()); await GetTaskListDescriptorsAsync(joinableTaskContext.Factory, serviceProvider); }); @@ -98,41 +168,44 @@ public async Task OnChangedAsync(Action changed) private EventHandler? _changed; public ClientAdvancedSettings GetAdvancedSettings() - => new( - GetBool(SettingsNames.FormatOnType, defaultValue: true), - GetBool(SettingsNames.AutoClosingTags, defaultValue: true), - GetBool(SettingsNames.AutoInsertAttributeQuotes, defaultValue: true), - GetBool(SettingsNames.ColorBackground, defaultValue: false), - GetBool(SettingsNames.CodeBlockBraceOnNextLine, defaultValue: false), - GetBool(SettingsNames.CommitElementsWithSpace, defaultValue: true), - GetEnum(SettingsNames.Snippets, SnippetSetting.All), - GetEnum(SettingsNames.LogLevel, LogLevel.Warning), - GetBool(SettingsNames.FormatOnPaste, defaultValue: true), - _taskListDescriptors); + => new(FormatOnType, AutoClosingTags, AutoInsertAttributeQuotes, ColorBackground, CodeBlockBraceOnNextLine, CommitElementsWithSpace, Snippets, LogLevel, FormatOnPaste, TaskListDescriptors); public bool GetBool(string name, bool defaultValue) { - if (_unifiedSettingsReader.AssumeNotNull().GetValue(name) is { Outcome: SettingRetrievalOutcome.Success, Value: { } unifiedValue }) + if (_writableSettingsStore.PropertyExists(SettingsNames.LegacyCollection, name)) { - return unifiedValue; + return _writableSettingsStore.GetBoolean(SettingsNames.LegacyCollection, name); } return defaultValue; } - public T GetEnum(string name, T defaultValue) where T : struct, Enum + public void SetBool(string name, bool value) { - if (_unifiedSettingsReader.AssumeNotNull().GetValue(name) is { Outcome: SettingRetrievalOutcome.Success, Value: { } unifiedValue }) + _writableSettingsStore.SetBoolean(SettingsNames.LegacyCollection, name, value); + _telemetryReporter.Value.ReportEvent("OptionChanged", Severity.Normal, new Property(name, value)); + + NotifyChange(); + } + + public int GetInt(string name, int defaultValue) + { + if (_writableSettingsStore.PropertyExists(SettingsNames.LegacyCollection, name)) { - if (Enum.TryParse(unifiedValue, ignoreCase: true, out var parsed)) - { - return parsed; - } + return _writableSettingsStore.GetInt32(SettingsNames.LegacyCollection, name); } return defaultValue; } + public void SetInt(string name, int value) + { + _writableSettingsStore.SetInt32(SettingsNames.LegacyCollection, name, value); + _telemetryReporter.Value.ReportEvent("OptionChanged", Severity.Normal, new Property(name, value)); + + NotifyChange(); + } + private void NotifyChange() { _initializeTask.Join(); diff --git a/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/SettingsNames.cs b/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/SettingsNames.cs index 6200ae8f810..be05198edf1 100644 --- a/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/SettingsNames.cs +++ b/src/razor/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Options/SettingsNames.cs @@ -5,19 +5,22 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.Options; internal static class SettingsNames { - public const string UnifiedCollection = "languages.razor.advanced"; + public record Setting(string LegacyName, string UnifiedName); - public static readonly string FormatOnType = UnifiedCollection + ".formatOnType"; - public static readonly string AutoClosingTags = UnifiedCollection + ".autoClosingTags"; - public static readonly string AutoInsertAttributeQuotes = UnifiedCollection + ".autoInsertAttributeQuotes"; - public static readonly string ColorBackground = UnifiedCollection + ".colorBackground"; - public static readonly string CodeBlockBraceOnNextLine = UnifiedCollection + ".codeBlockBraceOnNextLine"; - public static readonly string CommitElementsWithSpace = UnifiedCollection + ".commitCharactersWithSpace"; - public static readonly string Snippets = UnifiedCollection + ".snippets"; - public static readonly string LogLevel = UnifiedCollection + ".logLevel"; - public static readonly string FormatOnPaste = UnifiedCollection + ".formatOnPaste"; + public const string LegacyCollection = "Razor"; + public const string UnifiedCollection = "textEditor.razor.advanced"; - public static readonly string[] AllSettings = + public static readonly Setting FormatOnType = new("FormatOnType", UnifiedCollection + ".formatOnType"); + public static readonly Setting AutoClosingTags = new("AutoClosingTags", UnifiedCollection + ".autoClosingTags"); + public static readonly Setting AutoInsertAttributeQuotes = new("AutoInsertAttributeQuotes", UnifiedCollection + ".autoInsertAttributeQuotes"); + public static readonly Setting ColorBackground = new("ColorBackground", UnifiedCollection + ".colorBackground"); + public static readonly Setting CodeBlockBraceOnNextLine = new("CodeBlockBraceOnNextLine", UnifiedCollection + ".codeBlockBraceOnNextLine"); + public static readonly Setting CommitElementsWithSpace = new("CommitElementsWithSpace", UnifiedCollection + ".commitCharactersWithSpace"); + public static readonly Setting Snippets = new("Snippets", UnifiedCollection + ".snippets"); + public static readonly Setting LogLevel = new("LogLevel", UnifiedCollection + ".logLevel"); + public static readonly Setting FormatOnPaste = new("FormatOnPaste", UnifiedCollection + ".formatOnPaste"); + + public static readonly Setting[] AllSettings = [ FormatOnType, AutoClosingTags, diff --git a/src/source-manifest.json b/src/source-manifest.json index ddb7d14b617..dc202f285a5 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -67,10 +67,10 @@ "commitSha": "28eeb0947095a716b98b5c34454625708cb3ac76" }, { - "barId": 285013, + "barId": 286084, "path": "razor", "remoteUri": "https://github.com/dotnet/razor", - "commitSha": "909624c615247ce1bc4b81cd76c67f0011ce018e" + "commitSha": "d52cf7384867f6592a7a45f1696f8fa298441de4" }, { "barId": 285835, From 203d9c3bc8a4d970b12678e2bd2a87ddd31d7fb3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:19:15 +0000 Subject: [PATCH 04/28] [release/10.0.1xx] Source code updates from dotnet/aspnetcore (#2775) [release/10.0.1xx] Source code updates from dotnet/aspnetcore --- .../Windows/WindowsHostingBundle/LCID/1033/thm.wxl | 2 +- .../Kestrel/Core/src/Internal/Http2/Http2Connection.cs | 8 ++++++-- .../Http2/Http2ConnectionTests.cs | 7 ++++--- src/source-manifest.json | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/aspnetcore/src/Installers/Windows/WindowsHostingBundle/LCID/1033/thm.wxl b/src/aspnetcore/src/Installers/Windows/WindowsHostingBundle/LCID/1033/thm.wxl index 8adb2637d01..7489ae99819 100644 --- a/src/aspnetcore/src/Installers/Windows/WindowsHostingBundle/LCID/1033/thm.wxl +++ b/src/aspnetcore/src/Installers/Windows/WindowsHostingBundle/LCID/1033/thm.wxl @@ -11,7 +11,7 @@ - + diff --git a/src/aspnetcore/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs b/src/aspnetcore/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs index 689341ddc15..9d3fb830201 100644 --- a/src/aspnetcore/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs +++ b/src/aspnetcore/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs @@ -1158,8 +1158,12 @@ private Task ProcessWindowUpdateFrameAsync() { if (stream.RstStreamReceived) { - // Hard abort, do not allow any more frames on this stream. - throw CreateReceivedFrameStreamAbortedException(stream); + // WINDOW_UPDATE received after we have already processed an inbound RST_STREAM for this stream. + // RFC 7540 (Sections 5.1, 6.9) / RFC 9113 do not explicitly define semantics for WINDOW_UPDATE on a + // stream in the "closed" state due to a reset by client. We surface it as a stream error (STREAM_CLOSED) + // rather than aborting the entire connection to keep behavior deterministic and consistent with other servers. + // https://github.com/dotnet/aspnetcore/issues/63726 + throw new Http2StreamErrorException(_incomingFrame.StreamId, CoreStrings.Http2StreamAborted, Http2ErrorCode.STREAM_CLOSED); } if (!stream.TryUpdateOutputWindow(_incomingFrame.WindowUpdateSizeIncrement)) diff --git a/src/aspnetcore/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs b/src/aspnetcore/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs index 41a83e888c2..9ab5ceaa4d5 100644 --- a/src/aspnetcore/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs +++ b/src/aspnetcore/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs @@ -3599,7 +3599,6 @@ public async Task RST_STREAM_IncompleteRequest_AdditionalResetFrame_IgnoreAdditi AssertConnectionNoError(); } - [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/53744")] [Fact] public async Task RST_STREAM_IncompleteRequest_AdditionalWindowUpdateFrame_ConnectionAborted() { @@ -3618,10 +3617,12 @@ public async Task RST_STREAM_IncompleteRequest_AdditionalWindowUpdateFrame_Conne await SendRstStreamAsync(1); await SendWindowUpdateAsync(1, 1024); - await WaitForConnectionErrorAsync(ignoreNonGoAwayFrames: false, expectedLastStreamId: 1, - Http2ErrorCode.STREAM_CLOSED, CoreStrings.FormatHttp2ErrorStreamAborted(Http2FrameType.WINDOW_UPDATE, 1)); + await WaitForStreamErrorAsync(expectedStreamId: 1, Http2ErrorCode.STREAM_CLOSED, CoreStrings.Http2StreamAborted); tcs.TrySetResult(); // Don't let the response start until after the abort + + await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false); + AssertConnectionNoError(); } [Fact] diff --git a/src/source-manifest.json b/src/source-manifest.json index dc202f285a5..a4987e27533 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -7,10 +7,10 @@ "commitSha": "e6f510cb87812d56ad781d93ff0513cdcccd0eb4" }, { - "barId": 285906, + "barId": 286072, "path": "aspnetcore", "remoteUri": "https://github.com/dotnet/aspnetcore", - "commitSha": "390528c5d84ed166f4d0d42d5daa82a98b2686da" + "commitSha": "0e4a5ef86a40d2c4a39675aa5c93a3cee7365992" }, { "barId": 279211, From 04fa42d03f273dab6741ca630723c422bb6fbd9e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:21:32 +0000 Subject: [PATCH 05/28] [release/10.0.1xx] Source code updates from dotnet/roslyn (#2783) [release/10.0.1xx] Source code updates from dotnet/roslyn --- src/roslyn/eng/config/PublishData.json | 2 +- src/source-manifest.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/roslyn/eng/config/PublishData.json b/src/roslyn/eng/config/PublishData.json index 8f45614e6ef..c767dc77581 100644 --- a/src/roslyn/eng/config/PublishData.json +++ b/src/roslyn/eng/config/PublishData.json @@ -123,7 +123,7 @@ "NonShipping" ], "vsBranch": "rel/d18.0", - "insertionTitlePrefix": "[d18.0 P2]", + "insertionTitlePrefix": "[d18.0 Insiders]", "insertionCreateDraftPR": false } } diff --git a/src/source-manifest.json b/src/source-manifest.json index a4987e27533..d577dce23d0 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -73,10 +73,10 @@ "commitSha": "d52cf7384867f6592a7a45f1696f8fa298441de4" }, { - "barId": 285835, + "barId": 286091, "path": "roslyn", "remoteUri": "https://github.com/dotnet/roslyn", - "commitSha": "c847160676a0cbf91245c9ac873cf7519a55fa8a" + "commitSha": "31f3d76b2e55b0d474b37640fb0411de282186d8" }, { "barId": 285920, From 58a20a97f23196f9f06fbc5079ce63183a494bdb Mon Sep 17 00:00:00 2001 From: Matt Thalman Date: Wed, 8 Oct 2025 11:02:46 -0500 Subject: [PATCH 06/28] Use non-stable version for SB SDK filename on publish (#2750) --- eng/PublishSourceBuild.props | 76 ++++++++++++++++++++++ eng/Publishing.props | 46 ------------- eng/pipelines/templates/jobs/vmr-build.yml | 4 +- 3 files changed, 78 insertions(+), 48 deletions(-) diff --git a/eng/PublishSourceBuild.props b/eng/PublishSourceBuild.props index 3716a167601..4508c7b4bac 100644 --- a/eng/PublishSourceBuild.props +++ b/eng/PublishSourceBuild.props @@ -182,4 +182,80 @@ + + + + dotnet-sdk- + + + + + + + + + + + + + Blob + true + + + + Blob + true + + + + Blob + true + + + + Blob + true + + + true + Blob + %(Filename)%(Extension) + + + + + <_SourceBuildArtifactsDir>$(ArtifactsAssetsDir)/source-build/ + $(_SourceBuildArtifactsDir)/$(SdkFileNamePrefix)$(SourceBuiltSdkNonStableVersion)-$(TargetRid)$(ArchiveExtension) + + + + + + + + + + + + + true + true + Blob + $([System.IO.Path]::GetFileName($(SourceBuiltPublishAssetsDir)))/%(Filename)%(Extension) + + + + + diff --git a/eng/Publishing.props b/eng/Publishing.props index 9bee0471867..4115c507150 100644 --- a/eng/Publishing.props +++ b/eng/Publishing.props @@ -83,52 +83,6 @@
- - - - Blob - true - - - - - - - Blob - true - - - - Blob - true - - - - Blob - true - - - true - Blob - %(Filename)%(Extension) - - - - - - - - - true - true - Blob - $([System.IO.Path]::GetFileName($(SourceBuiltPublishAssetsDir)))/%(Filename)%(Extension) - - - Date: Wed, 8 Oct 2025 10:50:04 -0700 Subject: [PATCH 07/28] Remove trailing dash on dotnet-sdk (#2788) --- eng/download-source-built-archive.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/download-source-built-archive.sh b/eng/download-source-built-archive.sh index c56ec8753ff..89cd4c62335 100755 --- a/eng/download-source-built-archive.sh +++ b/eng/download-source-built-archive.sh @@ -80,7 +80,7 @@ function DownloadArchive { local archiveUrl local artifactsBaseFileName="Private.SourceBuilt.Artifacts" local prebuiltsBaseFileName="Private.SourceBuilt.Prebuilts" - local sdkBaseFileName="dotnet-sdk-" + local sdkBaseFileName="dotnet-sdk" local defaultArtifactsRid='centos.10-x64' # Use override base filename if provided From 52de1e98b73ef8e0d4edb596c166dc2379ae10c3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 09:59:47 +0000 Subject: [PATCH 08/28] [release/10.0.1xx] Source code updates from dotnet/aspnetcore (#2795) [release/10.0.1xx] Source code updates from dotnet/aspnetcore --- src/aspnetcore/.azure/pipelines/ci-public.yml | 4 +- .../.azure/pipelines/ci-unofficial.yml | 4 +- src/aspnetcore/.azure/pipelines/ci.yml | 4 +- src/aspnetcore/eng/Version.Details.props | 184 ++++----- src/aspnetcore/eng/Version.Details.xml | 370 +++++++++--------- .../eng/scripts/install-nginx-mac.sh | 5 - ...nstall-nginx-linux.sh => install-nginx.sh} | 2 +- src/aspnetcore/global.json | 6 +- src/source-manifest.json | 4 +- 9 files changed, 289 insertions(+), 294 deletions(-) delete mode 100755 src/aspnetcore/eng/scripts/install-nginx-mac.sh rename src/aspnetcore/eng/scripts/{install-nginx-linux.sh => install-nginx.sh} (75%) diff --git a/src/aspnetcore/.azure/pipelines/ci-public.yml b/src/aspnetcore/.azure/pipelines/ci-public.yml index 22258ffb0e7..6874ec344b7 100644 --- a/src/aspnetcore/.azure/pipelines/ci-public.yml +++ b/src/aspnetcore/.azure/pipelines/ci-public.yml @@ -518,7 +518,7 @@ stages: isAzDOTestingJob: true buildArgs: --all --test --binaryLog /p:RunTemplateTests=false /p:SkipHelixReadyTests=true $(_InternalRuntimeDownloadArgs) beforeBuild: - - bash: "./eng/scripts/install-nginx-mac.sh" + - bash: "./eng/scripts/install-nginx.sh" displayName: Installing Nginx artifacts: - name: MacOS_Test_Logs_Attempt_$(System.JobAttempt) @@ -539,7 +539,7 @@ stages: useHostedUbuntu: false buildArgs: --all --test --binaryLog /p:RunTemplateTests=false /p:SkipHelixReadyTests=true $(_InternalRuntimeDownloadArgs) beforeBuild: - - bash: "./eng/scripts/install-nginx-linux.sh" + - bash: "./eng/scripts/install-nginx.sh" displayName: Installing Nginx - bash: "echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p" displayName: Increase inotify limit diff --git a/src/aspnetcore/.azure/pipelines/ci-unofficial.yml b/src/aspnetcore/.azure/pipelines/ci-unofficial.yml index 30989fd4d25..28dbc0f1336 100644 --- a/src/aspnetcore/.azure/pipelines/ci-unofficial.yml +++ b/src/aspnetcore/.azure/pipelines/ci-unofficial.yml @@ -556,7 +556,7 @@ extends: beforeBuild: - script: git submodule update --init displayName: Update submodules - - bash: "./eng/scripts/install-nginx-mac.sh" + - bash: "./eng/scripts/install-nginx.sh" displayName: Installing Nginx artifacts: - name: MacOS_Test_Logs_Attempt_$(System.JobAttempt) @@ -579,7 +579,7 @@ extends: beforeBuild: - script: git submodule update --init displayName: Update submodules - - bash: "./eng/scripts/install-nginx-linux.sh" + - bash: "./eng/scripts/install-nginx.sh" displayName: Installing Nginx - bash: "echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p" displayName: Increase inotify limit diff --git a/src/aspnetcore/.azure/pipelines/ci.yml b/src/aspnetcore/.azure/pipelines/ci.yml index 16cb6f1bc3f..ddb60815d10 100644 --- a/src/aspnetcore/.azure/pipelines/ci.yml +++ b/src/aspnetcore/.azure/pipelines/ci.yml @@ -548,7 +548,7 @@ extends: isAzDOTestingJob: true buildArgs: --all --test --binaryLog /p:RunTemplateTests=false /p:SkipHelixReadyTests=true $(_InternalRuntimeDownloadArgs) beforeBuild: - - bash: "./eng/scripts/install-nginx-mac.sh" + - bash: "./eng/scripts/install-nginx.sh" displayName: Installing Nginx artifacts: - name: MacOS_Test_Logs_Attempt_$(System.JobAttempt) @@ -569,7 +569,7 @@ extends: useHostedUbuntu: false buildArgs: --all --test --binaryLog /p:RunTemplateTests=false /p:SkipHelixReadyTests=true $(_InternalRuntimeDownloadArgs) beforeBuild: - - bash: "./eng/scripts/install-nginx-linux.sh" + - bash: "./eng/scripts/install-nginx.sh" displayName: Installing Nginx - bash: "echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p" displayName: Increase inotify limit diff --git a/src/aspnetcore/eng/Version.Details.props b/src/aspnetcore/eng/Version.Details.props index 73fb3fcbf30..ffe9c35f973 100644 --- a/src/aspnetcore/eng/Version.Details.props +++ b/src/aspnetcore/eng/Version.Details.props @@ -6,98 +6,98 @@ This file should be imported by eng/Versions.props - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-beta.25479.115 - 10.0.0-beta.25479.115 - 10.0.0-beta.25479.115 - 10.0.0-beta.25479.115 - 10.0.0-beta.25479.115 - 10.0.0-beta.25479.115 - 10.0.0-beta.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 3.2.0-preview.25479.115 - 7.0.0-rc.48015 - 7.0.0-rc.48015 - 7.0.0-rc.48015 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-beta.25507.103 + 10.0.0-beta.25507.103 + 10.0.0-beta.25507.103 + 10.0.0-beta.25507.103 + 10.0.0-beta.25507.103 + 10.0.0-beta.25507.103 + 10.0.0-beta.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 3.2.0-preview.25507.103 + 7.0.0-rc.803 + 7.0.0-rc.803 + 7.0.0-rc.803 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 4.13.0-3.24613.7 4.13.0-3.24613.7 diff --git a/src/aspnetcore/eng/Version.Details.xml b/src/aspnetcore/eng/Version.Details.xml index 833b9a770de..0f0a7ebe0bf 100644 --- a/src/aspnetcore/eng/Version.Details.xml +++ b/src/aspnetcore/eng/Version.Details.xml @@ -8,333 +8,333 @@ See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md for instructions on using darc. --> - + - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 @@ -358,37 +358,37 @@ - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 https://github.com/dotnet/extensions @@ -440,17 +440,17 @@ https://github.com/dotnet/msbuild d1cce8d7cc03c23a4f1bad8e9240714fd9d199a3 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 diff --git a/src/aspnetcore/eng/scripts/install-nginx-mac.sh b/src/aspnetcore/eng/scripts/install-nginx-mac.sh deleted file mode 100755 index e7df86f57c0..00000000000 --- a/src/aspnetcore/eng/scripts/install-nginx-mac.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -brew update -brew list openssl || brew install openssl -brew list nginx || brew install nginx diff --git a/src/aspnetcore/eng/scripts/install-nginx-linux.sh b/src/aspnetcore/eng/scripts/install-nginx.sh similarity index 75% rename from src/aspnetcore/eng/scripts/install-nginx-linux.sh rename to src/aspnetcore/eng/scripts/install-nginx.sh index f075a899d1c..23d71043ed1 100755 --- a/src/aspnetcore/eng/scripts/install-nginx-linux.sh +++ b/src/aspnetcore/eng/scripts/install-nginx.sh @@ -6,7 +6,7 @@ scriptroot="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" reporoot="$(dirname "$(dirname "$scriptroot")")" nginxinstall="$reporoot/.tools/nginx" -curl -sSL http://nginx.org/download/nginx-1.26.3.tar.gz --retry 5 | tar zxfv - -C /tmp && cd /tmp/nginx-1.26.3/ +curl -sSL http://nginx.org/download/nginx-1.29.1.tar.gz --retry 5 | tar zxfv - -C /tmp && cd /tmp/nginx-1.29.1/ ./configure --prefix=$nginxinstall --with-http_ssl_module --without-http_rewrite_module make make install diff --git a/src/aspnetcore/global.json b/src/aspnetcore/global.json index ca40e9fd11c..c4cb92a9a95 100644 --- a/src/aspnetcore/global.json +++ b/src/aspnetcore/global.json @@ -27,9 +27,9 @@ "jdk": "latest" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25479.115", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25479.115", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25479.115", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25507.103", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25507.103", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25507.103", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.WixToolset.Sdk": "5.0.2-dotnet.2737382" diff --git a/src/source-manifest.json b/src/source-manifest.json index d577dce23d0..5eb190bc720 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -7,10 +7,10 @@ "commitSha": "e6f510cb87812d56ad781d93ff0513cdcccd0eb4" }, { - "barId": 286072, + "barId": 286219, "path": "aspnetcore", "remoteUri": "https://github.com/dotnet/aspnetcore", - "commitSha": "0e4a5ef86a40d2c4a39675aa5c93a3cee7365992" + "commitSha": "305280b3a9092b709b4449640e4d8db9a327d46f" }, { "barId": 279211, From 3f421476808214d4a11d71da8a47a86542ec5cc4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 09:59:55 +0000 Subject: [PATCH 09/28] [release/10.0.1xx] Source code updates from dotnet/roslyn (#2801) [release/10.0.1xx] Source code updates from dotnet/roslyn --- src/roslyn/eng/Version.Details.props | 2 +- src/roslyn/eng/Version.Details.xml | 6 +++--- .../Core/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj | 8 ++++++++ src/source-manifest.json | 4 ++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/roslyn/eng/Version.Details.props b/src/roslyn/eng/Version.Details.props index 4601885cfd9..51efebaf0a7 100644 --- a/src/roslyn/eng/Version.Details.props +++ b/src/roslyn/eng/Version.Details.props @@ -9,7 +9,7 @@ This file should be imported by eng/Versions.props 3.11.0 4.10.0-1.24061.4 - 2.0.0-rtm.25479.115 + 2.0.0-rtm.25507.103 9.0.0 9.0.0 diff --git a/src/roslyn/eng/Version.Details.xml b/src/roslyn/eng/Version.Details.xml index 5dc2b1d21e0..79cd3e0eec7 100644 --- a/src/roslyn/eng/Version.Details.xml +++ b/src/roslyn/eng/Version.Details.xml @@ -1,15 +1,15 @@ - + https://github.com/dotnet/roslyn ae1fff344d46976624e68ae17164e0607ab68b10 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 diff --git a/src/roslyn/src/Workspaces/MSBuild/Core/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj b/src/roslyn/src/Workspaces/MSBuild/Core/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj index 7cca46fc60e..54861314614 100644 --- a/src/roslyn/src/Workspaces/MSBuild/Core/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj +++ b/src/roslyn/src/Workspaces/MSBuild/Core/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj @@ -33,7 +33,15 @@ we are running against. --> + + + + diff --git a/src/source-manifest.json b/src/source-manifest.json index 5eb190bc720..9e6b331554a 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -73,10 +73,10 @@ "commitSha": "d52cf7384867f6592a7a45f1696f8fa298441de4" }, { - "barId": 286091, + "barId": 286121, "path": "roslyn", "remoteUri": "https://github.com/dotnet/roslyn", - "commitSha": "31f3d76b2e55b0d474b37640fb0411de282186d8" + "commitSha": "23d275e30097136b12a68d1bab4997148361d116" }, { "barId": 285920, From f448387a0e80f2fdeaec2d2f99ace7284fe37aac Mon Sep 17 00:00:00 2001 From: Matt Thalman Date: Thu, 9 Oct 2025 09:50:31 -0500 Subject: [PATCH 10/28] Remove featureBand pipeline parameter (#2793) --- eng/pipelines/pr.yml | 9 --------- eng/pipelines/unofficial.yml | 16 ++-------------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/eng/pipelines/pr.yml b/eng/pipelines/pr.yml index 150c23b9960..4591103b592 100644 --- a/eng/pipelines/pr.yml +++ b/eng/pipelines/pr.yml @@ -31,15 +31,6 @@ parameters: - lite - full -- name: featureBand - displayName: 'Target Feature Band' - type: string - default: 'Detect by Branch Name' - values: - - 'Detect by Branch Name' - - '1xx' - - '>= 2xx' - variables: - name: isScheduleTrigger value: ${{ eq(variables['Build.Reason'], 'Schedule') }} diff --git a/eng/pipelines/unofficial.yml b/eng/pipelines/unofficial.yml index 086c24197ba..d25e87cdd39 100644 --- a/eng/pipelines/unofficial.yml +++ b/eng/pipelines/unofficial.yml @@ -41,15 +41,6 @@ parameters: - Stable Preview - Stable Final -- name: featureBand - displayName: 'Target Feature Band' - type: string - default: 'Detect by Branch Name' - values: - - 'Detect by Branch Name' - - '1xx' - - '>= 2xx' - variables: - name: isScheduleTrigger value: ${{ eq(variables['Build.Reason'], 'Schedule') }} @@ -143,8 +134,5 @@ extends: scope: ${{ parameters.buildScope }} isOfficialBuild: false # Exclude runtime dependent jobs for any branch not producing a 1xx version since runtime-related repos aren't built in that context - # Will exclude runtime-dependent jobs when either of the following are true: - # - 'Detect By Branch Name' was selected for the feature band: branch is not main and does not contain '.1xx' but does end with 'xx'. - # - '>= 2xx' was selected for the feature band - ${{ if or(and(eq(parameters.featureBand, 'Detect by Branch Name'), ne(variables['Build.SourceBranch'], 'refs/heads/main'), not(contains(variables['Build.SourceBranch'], '.1xx')), endsWith(variables['Build.SourceBranch'], 'xx')), eq(parameters.featureBand, '>= 2xx')) }}: - excludeRuntimeDependentJobs: true + # This is enabled for all branches except main and 1xx + excludeRuntimeDependentJobs: false From 498fa572467f616303a2eef6829c010001c281f6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 19:12:27 +0000 Subject: [PATCH 11/28] [release/10.0.1xx] Source code updates from dotnet/runtime (#2798) Co-authored-by: dotnet-maestro[bot] --- src/runtime/eng/Version.Details.props | 14 +++++----- src/runtime/eng/Version.Details.xml | 28 +++++++++---------- src/runtime/src/mono/mono/mini/aot-compiler.c | 2 +- src/source-manifest.json | 4 +-- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/runtime/eng/Version.Details.props b/src/runtime/eng/Version.Details.props index 59e856f19c4..63bf3e97cf5 100644 --- a/src/runtime/eng/Version.Details.props +++ b/src/runtime/eng/Version.Details.props @@ -6,7 +6,7 @@ This file should be imported by eng/Versions.props - 10.0.0-rc.2.25466.2 + 10.0.0-rtm.25502.1 4.9.0-rc2.21473.1 @@ -100,12 +100,12 @@ This file should be imported by eng/Versions.props 10.0.0-prerelease.25475.1 10.0.0-prerelease.25475.1 - 1.0.0-prerelease.25467.1 - 1.0.0-prerelease.25467.1 - 1.0.0-prerelease.25467.1 - 1.0.0-prerelease.25467.1 - 1.0.0-prerelease.25467.1 - 1.0.0-prerelease.25467.1 + 1.0.0-prerelease.25502.1 + 1.0.0-prerelease.25502.1 + 1.0.0-prerelease.25502.1 + 1.0.0-prerelease.25502.1 + 1.0.0-prerelease.25502.1 + 1.0.0-prerelease.25502.1 10.0.0-alpha.0.25479.2 diff --git a/src/runtime/eng/Version.Details.xml b/src/runtime/eng/Version.Details.xml index e40ce5b17dd..1f28d582d03 100644 --- a/src/runtime/eng/Version.Details.xml +++ b/src/runtime/eng/Version.Details.xml @@ -1,9 +1,9 @@ - + https://github.com/dotnet/icu - 4c504bd8f75919cc512c456551f4229847da9e21 + a91b254e70decd379d76338b7bb171ee98301aef https://github.com/dotnet/wcf @@ -307,21 +307,21 @@ https://github.com/dotnet/dotnet e72b5bbe719d747036ce9c36582a205df9f1c361 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa https://github.com/dotnet/hotreload-utils @@ -355,13 +355,13 @@ https://github.com/dotnet/dotnet e72b5bbe719d747036ce9c36582a205df9f1c361 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa diff --git a/src/runtime/src/mono/mono/mini/aot-compiler.c b/src/runtime/src/mono/mono/mini/aot-compiler.c index 5349e634ed9..9598e9d3f20 100644 --- a/src/runtime/src/mono/mono/mini/aot-compiler.c +++ b/src/runtime/src/mono/mono/mini/aot-compiler.c @@ -638,7 +638,7 @@ is_direct_pinvoke_enabled (const MonoAotCompile *acfg) /* Wrappers around the image writer functions */ -#define MAX_SYMBOL_SIZE 256 +#define MAX_SYMBOL_SIZE 1024 #if defined(TARGET_WIN32) && defined(TARGET_X86) static const char * diff --git a/src/source-manifest.json b/src/source-manifest.json index 9e6b331554a..7a1e827cf9b 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -79,10 +79,10 @@ "commitSha": "23d275e30097136b12a68d1bab4997148361d116" }, { - "barId": 285920, + "barId": 286218, "path": "runtime", "remoteUri": "https://github.com/dotnet/runtime", - "commitSha": "05a3a9ba8860b076afc88a6bf0d455f2c3b522d3" + "commitSha": "d321bc6abef02ed27790e8da3740d253976b9ac6" }, { "barId": 277711, From cdbdb8f49a61a93d2ece59a66bed09e111cbb2ed Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 13:51:07 -0700 Subject: [PATCH 12/28] [release/10.0.1xx] Source code updates from dotnet/arcade (#2791) Co-authored-by: dotnet-maestro[bot] Co-authored-by: Matt Mitchell --- src/arcade/Arcade.slnx | 2 +- src/arcade/eng/Version.Details.props | 4 +- src/arcade/eng/Version.Details.xml | 8 +- src/arcade/global.json | 4 +- .../build/wix5/bundle/bundle.wxs | 10 +- .../build/wix5/wix.targets | 2 +- .../Resources/InnerZipFile.zip | Bin 0 -> 17755 bytes .../SignToolTests.cs | 109 +++++++++++++++++- .../src/AdditionalCertificateInformation.cs | 4 + .../src/BatchSignUtil.cs | 41 ++++++- .../src/Configuration.cs | 38 +++++- .../src/ExplicitCertificateKey.cs | 14 --- .../src/FileSignInfo.cs | 3 + .../Microsoft.DotNet.SignTool/src/SignInfo.cs | 32 +++-- .../Microsoft.DotNet.SignTool/src/SignTool.cs | 78 +++++++++++-- .../src/SignToolTask.cs | 9 ++ src/source-manifest.json | 4 +- 17 files changed, 313 insertions(+), 49 deletions(-) create mode 100644 src/arcade/src/Microsoft.DotNet.SignTool.Tests/Resources/InnerZipFile.zip diff --git a/src/arcade/Arcade.slnx b/src/arcade/Arcade.slnx index cc381104afc..a4c51eaafd6 100644 --- a/src/arcade/Arcade.slnx +++ b/src/arcade/Arcade.slnx @@ -45,6 +45,7 @@ + @@ -71,7 +72,6 @@ - diff --git a/src/arcade/eng/Version.Details.props b/src/arcade/eng/Version.Details.props index 39ca5e519b3..74f32236a9c 100644 --- a/src/arcade/eng/Version.Details.props +++ b/src/arcade/eng/Version.Details.props @@ -14,8 +14,8 @@ This file should be imported by eng/Versions.props 10.0.100-preview.4.25220.1 - 10.0.0-beta.25469.2 - 10.0.0-beta.25469.2 + 10.0.0-beta.25507.1 + 10.0.0-beta.25507.1 1.1.0-beta.25424.1 1.1.0-beta.25424.1 diff --git a/src/arcade/eng/Version.Details.xml b/src/arcade/eng/Version.Details.xml index b108dd09482..8e4ff3e2e9b 100644 --- a/src/arcade/eng/Version.Details.xml +++ b/src/arcade/eng/Version.Details.xml @@ -20,13 +20,13 @@ https://github.com/dotnet/templating 43b5827697e501c442eb75ffff832cd4df2514fe - + https://github.com/dotnet/arcade - 6275af47ebda0d394d4a5a401b77bc6f2304204a + 4eaa220ea860cee9fa61df42411bbf79394edd23 - + https://github.com/dotnet/arcade - 6275af47ebda0d394d4a5a401b77bc6f2304204a + 4eaa220ea860cee9fa61df42411bbf79394edd23 https://github.com/dotnet/arcade-services diff --git a/src/arcade/global.json b/src/arcade/global.json index a90a1ab74f6..b8b866ce354 100644 --- a/src/arcade/global.json +++ b/src/arcade/global.json @@ -12,8 +12,8 @@ "dotnet": "10.0.100-rc.1.25451.107" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25469.2", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25469.2", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25507.1", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25507.1", "Microsoft.Build.NoTargets": "3.7.0" } } diff --git a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/bundle/bundle.wxs b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/bundle/bundle.wxs index b7fb42ee99b..1c5db2ade1d 100644 --- a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/bundle/bundle.wxs +++ b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/bundle/bundle.wxs @@ -61,7 +61,15 @@ - + + + + + + + + + diff --git a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/wix.targets b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/wix.targets index 8632bcf50af..742bf80955f 100644 --- a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/wix.targets +++ b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/wix.targets @@ -340,7 +340,7 @@ - + diff --git a/src/arcade/src/Microsoft.DotNet.SignTool.Tests/Resources/InnerZipFile.zip b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/Resources/InnerZipFile.zip new file mode 100644 index 0000000000000000000000000000000000000000..333b5199c4e497b6da1970d2e95ca3e571eb5758 GIT binary patch literal 17755 zcmZUaLy#^Etft$xZJ)Mn+qQYSPxsfhZQHhO+qP}{{68T&I`YtHxQb`rV!wnFCIFKVP}SHg5S}n6^jX z>$_a`t7q1~Dib^V&R+LB`;A$z>L;|7njQ+n0mEFdn6z3AOW97V1z9leQZwB$jxeRO zQ(9e3Uh`{9OF!-NOefW~`i!QZefRah1-^uaxU%QPEk8*J4aFify_|h6T>EfX0uT!{ zmc3C6b8dWcr4Lb_nB4!edMr~!WB#0|w0X-RPK7TwJA~|~-dSPX$WzJAU;dD0pK|^w z{Use*>ihRy;B8F3I&(QtcmmR$sCJ8TjVp8JwEB=0l`Lt8yQ%E`H0}$9}~;7HfGIu!F~Tjq@yGC9z%n_ZLZmk zIJWC=RLrXz!(lXT>)nl~A7BVp^nT@;SzpX-Sa>XvUXZeAt<+;s2k@&bm=)~RBzm87 z?az_?De!XLUwchyh-`Px0Zf$+w}%hLf(+LU;TO>^4kl9r#K?r(S7i!>hzNQ&fdy2& z#tqYN3swvY)Wr(jw+VIA4&#UDWK;KS1_p`5%MaE^hYiFY4R%McA_pR4?TPI4i8NIY z^oA}M1FC9t1D0UZcd)e&l+&M;Iwr;l5_t|qyVil_WPwa8!c0HB)r1Vh%Q=s$=>^m8 zH`Aj*q!~8m#OTT}(*oU|<%10aX*C1(+-e7wY2}F?*(=%wZY4>$X0HP}^SP7^G(%(` z&6xzNRB}YrOC<`4;md*iJ}h)R4@59*j1=z+s=o3ffhL7=z!wRxf^1JUGtUYmNY1Vs z<7OA85%ci|ir|Z)Yoi0-0uk4LxYkNAuIG28Zgh!c%NGH^ykz^b)Kp;`~ z7cbyv?G6*~f@aEYu%i?Cs_%dojKL&UAio+P8_tliEvp5^)>5=9J&h*>>>t(8y=E7R zC#~Sit;8K13SiY4s0JT}?cLYw_w7f(2Z8Mf`Wkptps}fH==TIZqr|RJs2%~g*XPgbcTAc;& z&uy)puVuEbWG9^_*+q{X?)fmWbOYC%c*;_e@lw;l^6b(LmteN)Q!f^o<=JJCp2ZuZ zp4jcwas*V_RHc@Gu^#H)uaO$6fy{D>C+W%eeT!T8AghG}b37`1MSme3WhM>7bnHqg zH`FmaK#?;`!jPX&LGB97WuK0)>q2=2>9VNEt`+f(6mrmQw$!Kj=8GZ%hJ4IWDR?9@xs`P2?cpyf;o*JN0Fw?EDCda5~6AAo&2)uH`!6kL5@lLNp-96grpc zplEi(MkKtc3VE9hGZ`XFBiEqkta=2{zpAb2op>XxgTDM3PitC2>ISl1ncK>VXQ;{4!g_;6h77?!wDWQ?FlP2#-z3^{waLr?`CkM?=! zxmVKWh<<3eQJUh8>pu+fAL6@z*O35>2oR=?K!M-Tev7)$LuoX9)Y0DwtXHsY@cs3y zwPut2yFO=0hiC+X38}y!yZ^sN4<$eF60?L%fjzaY{!%0uSMJ5^=_ zTB8+Q8Ouw&b=bEq`uR~cXr7)~Jl%$fAK(0XxmBV3JRftV9E9h`1mb)jdAc%Qj6R?x zR~w6EOQ_H=Y;nS?fnl2D0USL*jK7mw1{-bQ1JDP*1QA2(^i;bb09{L`AV~?z3rJJJtRIO- zwDv|rHM!zY4@Az`L0A=;yY4`r<5pLQp}6qo-x$dl8oIRF2;$|Ul0Swo#!z$G(plGm zCOZ?f$kbn$9U7{bOh~d>GivqEx5lskKIrdHPOAiSb7V)*rovBKFftu9S|yAlISM>y z`A21tR@inewRzb;T$fVf$4lcrIaOz|H+Gbv2))nv2>QXX78J$1|@;QjQ{^1RL*#PZyvpcbq zmk%ew;md_Hr6$C4CFy3uk2@(~6_>_|{}mxF9ta_k{4TH>q^14LAZtEO>7%Qt5yfzouot_7>bOWduZk2q zVaEZS162onLeYSJ=r1!SO9u=ch~!{;n0k8%IcjrG>1j-bzPV*DVn$`bD_tiI47v-c z>KV>S8R-6bYx)Pm74)j!Uw`5WH=eoz+umKjI(o(b!lUcZY5aAs3c=cZ6IVy4h0;Dz@R13uL1>dG z6CIvXzJ@SBrcyVySIKmC?mNH*XGdYRJ?gecac&rgl)*N*%rnVINe3VN1cE z-G=GEZ~O2Etib8&=9%pPFF@-@NPy0?Y_b6Vp;NHeXuYHa;(Pj~|L4o_6M+$uk&FJU z)^N+(QDGngwg)d8;iPui(V2I5e^YbOZW5=ri+`&zilVnHzD7XSr79gjcYcc8;N=aO zHpx=gmk0o-c~5>-B~m5~M9iLnuHyO09C!Rbp^ZjiM zp=oEK;S%Oy_9Smo&Gqj`+Xm6Yuy^E}S`6Lm`p^BD5iB5D%u|VkA0C=1FCiiwqL9tw z;xT-FyE<_h4K?r{~(O zANR(V`7-`Z2eDPHxbv!ZN8`*8wJZ5MF{Jb%tdu)o%n^pR=sXVE9F!?Xp*}GSL8Y{0 zHwu#El3bKIu6Rz+?`heG9CftA0X8~Y19Ajm{QKF&a{uG3TCKH^agV1_&}i?{gD+)d zV|_!xlH)uE_}aP9ro-dnHUDZvA>1jca=cSVk-SSxT{eQOu0PjEMYB0{8F0%3@mvaG znhXG6&~Fp{B$=)E)j?4FT|Q;$^Rfk`WcBaZ4DaGsbc0SYmy;>{>mwr0mYQ5ifJ3KkUCSt5 z+f;*8mA!T~I6Ncs>@>EhD8!d#_MpMW=SgOKMF-F@Ddbq!w4qfjp|BW|NtJ{nI29u| z2obl9y6g-J-G0@h=2~h8^i=Iwqf){if(k+Y3sBW;De>&7-<|pQw`#VORGF-tN`aUH zT>>lZLAEdV7fG1C?qa*9aqaKA^;mCEY>S}fKV$$1-*K~+-VUj?!eflGTi{`|1-f9b zHqjZNhab3V7Q?djtG?F-{4(_{a8iUjJP9 zcW4Bk*eaSxA#U4wu#B5AO1=#Twb97TG?`HxFKwohI_vj)kc=?05eR>9XK=`qG5Y(` zh!4VSWl;OJQ%6=`CRUk{{mjx;^ufR|YW#VG*GtYYGt+-v052w0lby$jjG~?uOKyRh zGj$DR1kp^V1?$m<3Qu-tto1wn21PcD2c76v-UVBWE~2eE{jDn=szd(tMV4hcm~Zrw z<6_3RN?=7R7C;M2?`U;Zq>uT0-o{K4QAqmYuu)TV5Z0E)49i3s!htp~57Sm1GzrB~ zw4sx{WISLdT_W0+58p^sP09Wiscm%n^W@f0HtOx6vU^X~9_0;h%z|d}N?Xz09+cB% zrM8zj)7PevIXZ-DS39@;)>AobE*8}1frw@C2>0@7KL&?hKd!SqG``|-@1{|D*pFVZ zR)lfv!S6p)xi#leRr#!W_u^5Xd`sI3VIQsM{;LWeYO5$0(LJvc-AV|&6^XcT{g2r+ z%=kZ<)A4*@p(o-KQoYOf@*VSFfrwY&Yzl?YWQ+W~T93B**AWo=a@+pv$8>r=V%uU{ zpLu@_i)YaC1G4y`qzd^~z<7a#KGQ5|>78aX&rII(dsqhS>Q>3a`Yyd8GU|oa3|J3p zwW;$YA5B8|Tu9rag5!J|Za6zU`y|K{_Oe7Iwbqn?H%LQr{x#5%eUgoyN4-~4Wj zQr*`U9=(53-*ZvB*JmZ{?n3{k;NEih133^lA@%nvU4-sygK2t26s>cHqo~TnkcWFA z9_ZJIzG9wP(!?lBgmiPq|AE6Fz&`0x28V<7X~JV>E6U~?rZ8O#yJLVj@_w9N8c{{-|7hNznn%KrbL49 z?yJVI{M{R42GPGTa+m491sACjy6biu`@Y~ucs}`!QhJ(4AhoM!4L+&ttMRl;ZFU3@g?fJSxJ_J5BcfaeaV}AfXV{v!e>dtBBr-U;&akZ$g z^6K}P9e9@%3TVgmHEyjkJ>6+}KK$`(z658_oZ{cvk~E(epaWwDP>qQSk#??32HTa@ zalaFiZM9m-x1#PkUT+90_5fu~bp-b=4Bkj&#W$n0+a>=rP`!Kun2-CPYEff>LI@Vt zDTOw=rQ1_YU*Ou<`u4u@;-QRtNI_8kFqfvcoPOBKDcmvO)831#2rhW1hhgrqlr-NPcfDg}N z;{Bf9rm6Atu=#(Le)D_4-}LKOi$~#0BwVY8gFkH{S-)1dT6u>wHJQt!DbZ-qB&ArF zLkxxz5VY^t5(_syt$)TBU|=VW=SK^OGzG3_taG~sdSk1GIa}hEh+e`df)s>>ZH#*S z*~x;Jh=ZkmB?f0Vc$e?3wjKFNh@;RCuFrXDI_wi8pD}tS* z+>~K41=j=swtuvOXGzu0byVK099OfR`VbM~LQq%nH85w}S{T=5Ry!yW2<8yr zC_U5xu9pJHH&inCT`AVr7z#RPc_?4_Q?mp=X_&{edLKDV@Aq4ek6wLK8P)HAI({XKs0*23xH&MaVE=HNh(;J@EOj2kya&WVb-YxAr^rDo+EkkCcT);crb5 zk^dTMAoAfSX8AsReh8Y+u?bONH0ZiScQgm475xiuFLuQgY0`sFxTizipreYIjc&X@ zWkYUr=)EfY$sdo~y=7M6K0yTZFH z{+~~nA)%vODM_%R2sDqMQakVZH_%w}NO9ncoSIU4uN#WeI`(gstjV?$lwxxDK|y?k zWt*D35#a6>m1f4$KDyx;U`x|>_#Rjj2z_Wj6+BXk;S#l$Sl0Qp!O=GS&XLi?EkT>5rZF8fNf~QS_vFe({UfHcBk>zU(RR ztIw6+`)a9nVQlW|!dRb0s4Y$aeZzD`w0n7~kk<_$49c48q7KXw%vwSqAz17=t6Owj z>|El_@U|ZTf`_X(WQ4z+?zJ$S>2uZsjphQiamvjr4agC{54pPcXDejob_5%?!Hi1P z3mLRNC{i=;GU|7m^)$v>&1De|M!=ibGy;d5#pZH;JUdwle{wNK9t46X)6V7c&Z)wvQtUKL7(wjfH;Lw*xY=grehv8} znR$}4L6Ko`w@SN3d zQ}iVD%99h*7xWyPZkV@`EZ;Z_X_vqnRlu<2=6JpIjG;Y$ZyLRso&|s!e9a`=lUHU| z>3@N_)_g}YN6L#gjWBYxKcI>cl|2}W1qz>(qzMa?@JRq%#gkNe!qg&G$i=5B+LGnL z3%b%yRMQ1$N*)Opyh7(p(v;ME(&u2s;M)2)GX+f%3%Yd43&PT~rA^rjl~i{5OLA7A z#g$am#b`nM7Yo3g5G4Npm-c^Ahjdbo z;A*C#ce_ljttYxH2Hq;m%d>VQMyPsoH?=a)Bs0Y<}kj`xs#}(fd37k&D7`UYMkTSo8wOVDN>e&%z(1v>eo_F)amZ#RpppCX;>q=~>trvENX`YIU7Bucd4CQ-BiA+7+8h%shTMjy5-wIRv0dzgMh>cKgUto~e@%DyoF zpdd50G9+)&Ak{zQsfeC|0ZC!@;zM--#aij$Ba|QCngO!8 z`9%Pq9n5<>wz33t@o+y6E--DW`T!C}Y1)W%p!--scm_rxV@g)1 zS3_UXfD$U`OZnG_Ch6kjcr0TA2VyEdz4$V=E@HfOH1iDAI}IonHefhz-2}Aw1po&z zdT@MzD4H-9QyB#K-ex4b;94-*n<$XXyjK!rmU&lyY8k9lClp<Y@7Q(1rnz4nEPbXqY>1{M;Ki5=mh<`b&%(37@UD#6n<#MYEAah1)i>EfrG@w; zW(VVuEgKpws4e6bgqLZhi{9c!VwM}~bKnNW<1(4~_z|8|sRT1y!h*8JNK(VX$SG|y z{5h$B-4f*`eUUoQbVmxs^fz|Nl^+wb_%-7~Mm+9vLGoA_ZCG%GTp!%O#c~;P^P66IU^1!04zmuLrS6tWFN~RAg?`$ z9=ij?JRD;w zq$0nYzD^o<$r+UowdaJ@g> z!^Hr+aVVK&{X$tSX?`P>zvyg1ZM7M9*7clQ&OWO>`HE1e07Kh>t~c#j9`HN(z^u%y zyjLQjH~Fq7%I>(^DoHg1`5~l5aj!vA4u3{M&*5fB0A^2i4u49*&k}h^0BCAa>8-3( zZ{d{UooV_`>a6+O@qlj)xxkCUK;!G*L>cFY%!cxR_&)%{Hy_ZBcYaW1AXnfRU;^+d zV4q1)2vtZ;gf_4{uRh(r#5i`~H|D)>B2R{S;4&b6cuiPM7)`)$>LpX_4I|MXLk>f% zI^?@s;Mc3S-OFyg3oA%ka9xl$ctJ4Ef3?8ZkX~qa7=4xgtH8U?elC5=f)I5`jG%Xj ziY<<}sWz(}p5_m+fjzl)9C;GTZa&Hkd)GM9`~KVWFSGO-ulv8^DvR5Cl+eUo z(omlPn#`n4Xl)G#k8#^Vu~;t>y!^C(l*vw@BN_tcXwU|Tu|>+@+#OmmCD0WFC++Ut zNb?oRqNIf+QZRhb0 zMPanGEMdYG2p^TlCvC*cP~b&N!f3}4*o&M|LLjaOs@9p^YjCzo7rQ6xIF$t02NBOwHC-^eD01^sI+b3?OB{FV%n7|1rXq@s*Z*aC>RL)3A+ zR7_OKqAFt6W#l0de9W3oH7cQZ5)ncBkja5gUQVz)1V8?a75r z&gYepVd*q-xE}{qtIll@kF81YIS4_t)ru#NC3dCw1%VrMBXT>s*l1qD@?&0OD_(P3 zvj#c1u&B#tb`go?>O{EJ(-!tzrI^Yk(k>-xF;J2qmm|Q!tnJFZocGtQir{RIpARV~ zxXP&~5>2>ua0XE@uf~O%{V{?08{QPouZxOA2H@qvwhfmpE$pD}5V{;m5FiN-s>56r zRc+{u>2bF9?gz3*`RfGNg-L>_UtzXzEd_;+Z7r7WCc~m$;JOOcpBGg#S(ST(Fb%)= zsYc}gqM{c;L~Y$f5MqR@%q)-1e5O5MgJc@a|07(+jmj)>K8SKuu+I%G((92lMouH$ zc2p|38j+_1wLn4g6z4BVK@;MWlcd1QA!ONHSw6pP$gcEynK!5f`jPQ7i`(^~pNOys z^a?2m+&X=dXc2m4ad&DKuSO?44+_yFmMc30Ia#UEy(#nj+_Jb4VDJyeun9PtaNyP{GruG4#gaFC3X5hmfP z!MOiJUiZ@i>sZz_sX5hGAoDc%J-V^9Ac#JA7g00;qlHc0q~``}+G z_)rz`j$RTG-9oTg-STP6_2Tl$-8oB8w`=rU{(XCOyCG0-FhqBF(Jo$-jeGo)%`@=+ z4*!MmqwW*t8|E9~8-43&>jKA3;PSO`UVBxJS0x$+thK+vn97$*XUt%{xsJfz7orv1 zopWtuZ~U9l9oU`Oo$8(T4f)b~)mz6OI=DWy-3SRv}j@cPYEpG|Ou3u?`pm46z!0bf34K zqpGC5<2|~c1fSfdF|gxKceQVLrN2u%)xNVohPlVSqfd6GTs2HIsF~53r<*3Z7|5F*Rj}TeG+jMV{uzkFaUC*sExe@>C*BRLv z>zT1R**(xbj{X4q?sK=s|6}k@`bGF|lh5zUUE>mxz3ck3^bWLSGSt5Np77{8!;u{_ zu{9B#OqYB~)7hVStLmc|UIBLoU#3BkIZJOGsl}o*&R(Z?bv&XI9gD@0&OEit$iSYO zHaX=|=hTPCAz=uLv1&jtrI1ZBg`Y_5R^BZL{iT z`G8t^P6ck{_;qtZIIm{G-_G(c_D#;vH>bVi7er)?_1F17@&AB`*E*hVy2H)_ zul27x-j>CBlL=p@-=^~>bXqO-@DP(Jw$zd-w$LV{ik`*Y37EAnHLpfh%Bb%$3ro~V z5D$K}#Jt*;dBo6GmY@a+As7pDWOVPsmco$5 z0JB+6CsXMx7BgAtTGbyrKcPj)@iDK{9O3*T59?CD&n)2_Uh{`WA5FiNmHdTIKF-T? z_W&KlsqSs= zXm7lA7it{VH5wGnmkmoPXMx+O(joFG>eNy8E48E<^$=`1_bVSU#C^e zmi!mRgUbl^Kf7#zvt2G_t4&S1Kd_cdBn3Zr5>Z5<$uC~}xVQ4P?=!9S^ZYOsdO_HR z!z6~`@bEAg#`{ zv{owSxDVR=?C!N&$ffUxsUj&nTvG(ev78N|_@a3cG)61bauA{cVnaGZ8XRaVmmwI6 z&ZJd~f!ex8q;jPMUt%7ru^e^DI=6v6Wf%qny1Cf*Tr$`!1>#=Vq~=Re3>HJyI5FDy z=usbXEElo0U>CYW07jf6Ef~(qG?=`d{pK!H*Zewb zAHMevyxtWYckF1KyT>@8`*3Le^qxBH!uoO?I=T4Yap`WIw7V5TJyvHaAYEP?|D6gu zwte93S%192*pDsAz8fo!3Yn4|Tc6NWYoh6q8~VaA90T}!xK!C&_gMt|!~VQ=JQpA= z;KkbQ|M`@8W8lFVeBpF_t1--^E-o>2 zedR66iyi$yjaqx#RZFS??;D#K`7S#MQ|pee%s6KfZ}INBB5Hid!*nNu#-`$*O{lvm zz0ucG;^gQ@Rh5V%8~w9I_h-oi2stwzqbAwvpYO3~W_0i)LG!HXg5(t1cgGdJ(jT2= zJo7pcH?A|1m*#Zu#3yX7dETeo9k?BE>E6ZeeS@4rnT5c`ZI=+<%lUe;rU` zJPn+`KARy|ssRSUihIvru4N$Eh`f7h#a?px)Nt}4_K~Cj(X?|m@~E~1n20?6EI&`j z=ID7^kmc=_A28_s%ZtmvD~C7xjebAnxl!fTBiPZLAwHp_&&t@XdFc1l(#p~$TL4@> z06zr#H^PFI`0B>lLKV9R*upPxY5Q?Uz;zbY-*O6CR3r;Ds8>13bLCNqj_;9=+0=G< z!Krp4ZsXMEp0s*|*p&6-Kuxy}aW)^p2wlqq79$ZwF}kC8#s^Txn!m!1<9rX=#dC$@ zwMk!M6WC1LeB)t(B->m=&p$-pQuU#IYHb({!4D>9_h_dCXvw8iXHRB%*=a>nz7}(giaDPqL2N||TI96NG%eJ7}PDfkr zkUMih%i9x1T5+@GpUk8Vza8c32mi@3CGcK)zjG>G&}AW(3KF8qccS7E#QPNu8*OX6 zP%4vng89touo-F`<^pERkM}oohlm`QDL3zmcH{pJCN{DN0t1-o&09&CdWog$uT25| z=&>%<+WpI}n6^@ujQdL%B<6exrb(d+K&x!Vs0GjF>$+>0O)mt@VJQ0CMv1*?6|^(v zv=p&_u}8M?Kdn$w_Qye~XnTnqQO-9K^s+Jfsu$C=$MG@3X-Ul^YSn+IOE{L&9Xs+- z+bbUr=iRCw} z2y1emEG;X)x92Noftf6lFc6j0*@s4KCO&~o*r9kPHM^!a_Y_k+Y;+q?>{RQ_vDr(Z z{`0q((y_O?FzW1|mq~rubAaZF$t)%1kmc0G7=o-_b<|bdv3LvHZb5}R#Jk0Tb}4!1 zc9|Bd6}+s`c*p4v(Ywv~sEKy@NMoEOFO`fM zPvCM@1Dn-`Z&|V&2{IsN~oNjD7X<$+5&A{g~NC}ztZ$4=WiF?IbYS~ zlg!m8xxKP^(ccb)Pt5_#9vJB{*BHUh;Xlj?c357c-w4 zCGKO~#kPGRhNiJl8|IGO!4to$NMh)w3!rBiL~NY)`Ib)h>fK!eUovjgId<+b6i-eC z?!^v51pW-*Fd8Y;$wehZa%WLhgm^ZOxRBj0Tx4bI}gt(Lihp<#S@m;<6cF3qMv+;`0ZP$wn&R?E5^;?Cxa2GlcsK{r4ngBZ%SrmcFqO41?mJ-=!ce8;k zgILIOV)4n+ zk(VO|(XW64yqb&jVg4>vp64tpPo@U)JZXRQ<7l}iu2eJRhcqX6urwJM2!URbJ+Dq| z8u`BwK`pf=9e!v>3>T-wQd2%hTJ51o>0SCl&X7>2ez{TPWlAWqdHYUUrcsLcq^4F z_mVkN*m>a$1f!TXSVTZlUO9!MAPcaU|12;95%Z z0`6hP=fb620ef@#d+Ao$eftR?Y5q$odLI&QCMh=5EeN&CL@BYq-9E{lw`pqc(?$S!RUe!_a z0o$eq?v}1`baM)mwSps^VSh_I_~lK_!BMSh-!l0qZm$k*(i2b1Gk1>{!*r$+=I|E% zjqp?JXE8sRllwdS?%iZypefEhb&l)8VvE^a`x+xBmE~bn*j&O=oaK;a+i<2SgU)0@ zqdvC#N~3P_o<hwD<5bBN;ruT53w_k>l#j=Wm`?5y_ZRjD zfe++I%LDFfS8QY|*oUy$Lio0@w7f_tV_{@_ueXTLkHEgtBkZQQ>_zGW!#RYY_?CwB z#uJHJ|cazMlOS?F}*6C1Va}T9$*B)>8SkkpVA(B(0D36t zb|54&nQ$P){1~shrkT2SaofK-qQGm>H~2tfCYZawR&BS0R!JY8Pf#X_0Sv-FwP_GW z#|@3SKw{or((Th(8(eBD8(0LO*)I2xTm6K#fX6K%K)<<8ibfymQDz}!xk zuPP`S((hG$yMSHfwEKc0|FO>aB3Jxc?&NTNtA@);jjX{R*G&LZKnVdWF0Da_b!@=UsqZ3%u&lmobBG21V79@MY%+`X^z z%m4_|3g-^$niYkWWDk17-b;get~sQDd8?d>mtwETFVc$c1fd4@D1I53t7w&$FuD30qF}w6T`B?}07Mv1fiSw1i{j53@>;O`%^28q}>D z-KQ7F0{HlS*b_FmRF4;dkDCMlI>kR51gfW#-!yyYDid9LC0pcb^DMDzeUm0FLzHvA z#aj`td`~zNtEP=RfPA;AXpfOmnc*Xck(;s8L{vjKE{#{y$ZK5xysd_C2uc_+Pu_oh z1k-Dz!%c~DPwT^`G+MG09pWR2*Vmcn5B!vB6Kfi74Se5ZwFn|JHU0UZtZM?2kXNP^ zHePG;#aByyiJ0C9MIk)b`wN;D+=$EaJ_V@S!AE~7%?M>TIcOEVjXW)>1m<%a8>{+e zZpV2Jj}cS`ooKSX6k28pLX~TroNrv1Yi5LvYqOgl&yg?2?so4-t`6pN(C)!4S`+Cu z)=8+$Z{%U3kIGA8lB(8pq)X2p^m%yHd3}b%3ng61CFJ`^Jr`UczJN>PPJB+59TqDW z*3q0P8_T2U=DJ;!-tsAVF8UncUfW39x@RPrRnkUtrm<3obGqzcuklUToy}DE)>USp zGhNnA&Z{ClaS$mUt#Sx1&Sfzj<%RYhw{ND6SFJonN9KfmXd$t#x9LVjvu7l&@aVTv z@mkjl={?nVle_wnDNmV9b=!mRjMh2c@5x@z)e*Qb%kH$JOB&C)9-K6T!|#nKNlDFP zuIbm4=}IC|b0DydJQoJ;Osy4J8SYfWo{6_+19MKTV#npc`7emuP4C+TnQOWzwe`^g z;?4Htl%U0hjjgiVj&Q!if=5qbWL3}nHwj2Q%fj)S+pF628I6BJI(H74#OF(9vGADa4L9&r(m zkeNw`gSn^WjuuTuF{^N9$s18w(EpM_`7rTi%@CQlrO2%0nXUkgS0xJVDHY zN%X}1_m2XB+=g;VC2K0-LdlYDWGatykHj$pVfP94O#T>rI36{%8SH&7YxYK=oDO&Y zqF9gEFV4dy-_AU8zt6-c3Xv?6^x6@Ggr1aX8yY9q$mK#3#;=FW0<>uMW2&70wNfo3^Z4kL zk6klHp5rfFW67CZ%M!R=g6ky}pm4PIEngGx0IJ-{Dc?+%eU2i9zCvc7zB|Q|EoVM? z7eumeeT+$k8g**=bYoV)F6#Ft&w_hkzWEOl3Od7R&w=PLU2x52sL(~QaN{{f;o1~~ z_~Qce_sG~?Yf9a}*qeq<+cQjq0aLn^?|{*@jg^~5wX^Z6WSDs+b!vdgeIt29)l^~q zz2K_z53D^2HJ7`z1HvgEYI#voYiO3gvA!sOj7wAm3jyh0%Ixza%@t~*Qp^*2E2x3g zb|D^L8u&ja>Ync2`rQ^SnO#i$wjo68m^&Y+Y9a@;{?`=I8|}EJMlU^Tag^8$$>`>g zKHvr=l?{Qz9$6Nit5$etZrB(YoP9(XM*+99QXR$(7<&`cFKy`MXr}{RdQ?e`G#Dnnn5@QWREmf>KagV5P9+lbr0K`{6;c75d}H zD5pA8`Sr#vB5*ue^k}FwdWW8CIeE@vl4q{cEAOxAZg&aaTL|J-Kidg@xhS$?*7KBs#mN-CUx)A36n7PR~QiN$2M^Ecf$ zo-(i7uInNk&b!~uXVZjUzY--Nau>t5ZhqXZt!z;Ug28k=V30vq~7s4V?Sfd@q_V~B;yW4>d#nW9#~IIYxYBE zOE(r@jDeR}WZpoDyBtaug=kBN#Mt7%*BF2EtU0F=4kK-!X!7EiOR)C)}z9vLrUoKU!9x4c)BOxQiBy545^usxlq%2anrqAO&@ekA28UT zi&&e73hGY zKb_?^W;O@Sb#~4vCk-m&P`OBgcy}u)@Ho>zEaLV6QT*@HC3!=~2@r`Qg zL?r{M7Nqlyk(in0rVl@7M}hIG_*YKzs4#eudxFrh=pFF@y5VRKtfss zB#_Tk5N7UlK{gsjtS82cC@*3Zgs>w2nq&Z^<_Anr!a;!~c;Z(6y;mTX7~OnVEbc^e)gj2z^NpJWDdlRP9oBof3i|F( z`0@5&Eebm#HsNoDd9Nn>*kARqXP|-jc3)DkzwPJq20#0ME_gS(6PnX|qUX{4gEyCPD?QBQcN;d)5<}8+` z6tkAA3q-dp;+0TwYOBd|zOm|Hzr$LF3vH4nITQIrZ1_3DCoWsmD!y-0*OhZg?M^K3 z+d}8-kk( zKNn5*Hx!#&Q)PKg@zio1!G?0z-3m)TJTSQ5=#cVB+NU@tyO8TasP56fY2Ur(Ee8%t z&8jile*WY%{%&XBAOkP!(V#p2*UYr9Jh;nhRkSnhyTHE3A<>IOxejf8nyq}l*x0l3 zXxyp`kM@1>xTk5c_^8CKXEK$amAN!i9+{=97pg8RYZa>hn~>vp(PfSD04vrz&)5g&Y;zxJLGI|7i|MWsd3(o0rx;K6chcmMd0ILieym_7;vj@7KqcefyRh zZN6;M$t8Ptnr_{>b*t^wU7AyKvhSK%+1%P!`FiQ$+_ll$w({mr($dcVC=zfYJw1Az zTludu?mhn>pSS;a?e+Qzm&_m3E-&cV|N6dJ@cCtWNu1z9_E@va z*Cib8z8!!2R_%TLeg6*q^ldKR+{f!~{=jFloNu29w{*d}TLBN}@V=|bJ8|o%;DwVh zeCO6r@p$s1`S82G-r3tHtge0Cy{@b$;Z0v`_*}cf|DW&2?b`ct=gWVR*;0G{&xv^O zao=Bkd70`@b7%U*3z;AL$P}%(e%+_aV%aTcWMAda`ybq|q_!jR-u|i+`OaJP4m@xF zU;gBR;iAvCe9l(({`Y*UzB795`2*Sx-shcJ_~*t1{jT@Iss`)yzDNs~R$e)B!P!1; zQQSvg>6>cmZ)P==1Z@Eh;_dBU(97)0_e+1;)+a1$WDfdqeZ0Rgw%Yomn9FUG6z$`h zzrU^dl%sUZYV}{oJ(U?VGOxFpt$nw<^;V{GomqEX_JwusJ=1TeB!(_a65;+neSydl zi*6sL@CTgI_nuADnb<6U*WjdHb97wtO%5GbSc>d2QHgk*%lyWdzR=k`^XtEj_vJfoxjDguY4*%k zu`4-C)GoZ;!aFUeW!aJ+8v}21Wo_=bT9zQQG3GW~j`Sakp6#+a^nL&a-{fw6Y0k&W#Jo`Zrh=?F9w%Y() + { + new ItemToSign(GetResourcePath("test.zip")), + new ItemToSign(GetResourcePath("test.tgz")), + new ItemToSign(GetResourcePath("NestedZip.zip")), + new ItemToSign(GetResourcePath("InnerZipFile.zip")) + }; + + var strongNameSignInfo = new Dictionary>(); + + // Overriding information + var explicitCertKeys = new Dictionary() + { + { new ExplicitCertificateKey("test.zip"), "ArchiveCert" }, + { new ExplicitCertificateKey("test.tgz"), "ArchiveCert" }, + { new ExplicitCertificateKey("InnerZipFile.zip"), "ArchiveCert" } + }; + + var additionalCertificateInfo = new Dictionary>() + { + { "ArchiveCert", + new List() { + new AdditionalCertificateInformation() { GeneratesDetachedSignature = true } + } + } + }; + + ValidateFileSignInfos(itemsToSign, strongNameSignInfo, explicitCertKeys, s_fileExtensionSignInfo, new[] + { + "File 'NativeLibrary.dll' Certificate='Microsoft400'", + "File 'SOS.NETCore.dll' TargetFramework='.NETCoreApp,Version=v1.0' Certificate='Microsoft400'", + "File 'Nested.NativeLibrary.dll' Certificate='Microsoft400'", + "File 'Nested.SOS.NETCore.dll' TargetFramework='.NETCoreApp,Version=v1.0' Certificate='Microsoft400'", + "File 'test.zip' Certificate='ArchiveCert'", + "File 'test.tgz' Certificate='ArchiveCert'", + "File 'InnerZipFile.zip' Certificate='ArchiveCert'", + "File 'Mid.SOS.NETCore.dll' TargetFramework='.NETCoreApp,Version=v1.0' Certificate='Microsoft400'", + "File 'MidNativeLibrary.dll' Certificate='Microsoft400'", + "File 'NestedZip.zip'", + }, + additionalCertificateInfo: additionalCertificateInfo, + expectedCopyFiles: new[] + { + $"{Path.Combine(_tmpDir, "ContainerSigning", "6", "InnerZipFile.zip")} -> {Path.Combine(_tmpDir, "InnerZipFile.zip")}", + $"{Path.Combine(_tmpDir, "ContainerSigning", "6", "InnerZipFile.zip.sig")} -> {Path.Combine(_tmpDir, "InnerZipFile.zip.sig")}" + }); + + ValidateGeneratedProject(itemsToSign, strongNameSignInfo, explicitCertKeys, s_fileExtensionSignInfo, new[] + { +$@" + + Microsoft400 + + + Microsoft400 + + + Microsoft400 + + + Microsoft400 + + + Microsoft400 + + + Microsoft400 + +", +$@" + + ArchiveCert + + + ArchiveCert + + + ArchiveCert + +" + }, additionalCertificateInfo: additionalCertificateInfo); + } + /// /// Verifies that signing of pkgs can be done on Windows, even though /// we will not unpack or repack them. @@ -2590,6 +2677,11 @@ public void ValidateSignToolTaskParsing() }), // Signed pe file new TaskItem(GetResourcePath("SignedLibrary.dll"), new Dictionary + { + { SignToolConstants.CollisionPriorityId, "123" } + }), + // Sign a test.zip + new TaskItem(GetResourcePath("test.zip"), new Dictionary { { SignToolConstants.CollisionPriorityId, "123" } }) @@ -2621,6 +2713,11 @@ public void ValidateSignToolTaskParsing() { "CertificateName", "DualSignCertificate" }, { "PublicKeyToken", "31bf3856ad364e35" }, { "CollisionPriorityId", "123" } + }), + new TaskItem("test.zip", new Dictionary + { + { "CertificateName", "DetachedArchiveCert" }, + { "CollisionPriorityId", "123" } }) }; @@ -2637,7 +2734,11 @@ public void ValidateSignToolTaskParsing() { "MacCertificate", "MacDeveloperHarden" }, { "MacNotarizationAppName", "com.microsoft.dotnet" }, { "CollisionPriorityId", "123" } - }) + }), + new TaskItem("DetachedArchiveCert", new Dictionary + { + { "DetachedSignature", "true" } + }), }; var task = new SignToolTask @@ -2670,7 +2771,11 @@ public void ValidateSignToolTaskParsing() "File 'ProjectOne.dll' TargetFramework='.NETCoreApp,Version=v2.1' Certificate='3PartySHA2' StrongName='ArcadeStrongTest'", "File 'ProjectOne.dll' TargetFramework='.NETStandard,Version=v2.0' Certificate='OverrideCertificateName' StrongName='ArcadeStrongTest'", "File 'ContainerOne.1.0.0.nupkg' Certificate='NuGet'", - "File 'SignedLibrary.dll' TargetFramework='.NETCoreApp,Version=v2.0' Certificate='DualSignCertificate'" + "File 'SignedLibrary.dll' TargetFramework='.NETCoreApp,Version=v2.0' Certificate='DualSignCertificate'", + "File 'SOS.NETCore.dll' TargetFramework='.NETCoreApp,Version=v1.0' Certificate='Microsoft400'", + "File 'Nested.NativeLibrary.dll' Certificate='Microsoft400'", + "File 'Nested.SOS.NETCore.dll' TargetFramework='.NETCoreApp,Version=v1.0' Certificate='Microsoft400'", + "File 'test.zip' Certificate='DetachedArchiveCert'" }; task.ParsedSigningInput.FilesToSign.Select(f => f.ToString()).Should().BeEquivalentTo(expected); } diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/AdditionalCertificateInformation.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/AdditionalCertificateInformation.cs index e7e2ed2f4a2..06f87035dee 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/AdditionalCertificateInformation.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/AdditionalCertificateInformation.cs @@ -21,6 +21,10 @@ public class AdditionalCertificateInformation /// If the certificate name represents a sign+notarize operation, this is the name of the notarize operation. /// public string MacNotarizationAppName { get; set; } + /// + /// If true, this certificate should generate detached signatures instead of in-place signing. + /// + public bool GeneratesDetachedSignature { get; set; } public string CollisionPriorityId { get; set; } } } diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs index 1eaca00b273..ecd63cf0009 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs @@ -554,9 +554,10 @@ private void VerifyCertificates(TaskLoggingHelper log) } else if (fileName.IsZip()) { - if (fileName.SignInfo.Certificate != null) + // Zip files can't be signed without a detached signature. If a certificate is provided but the signature is not detached. + if (!fileName.SignInfo.GeneratesDetachedSignature && fileName.SignInfo.Certificate != null) { - log.LogError($"Zip {fileName} should not be signed with this certificate: {fileName.SignInfo.Certificate}"); + log.LogError($"'{fileName}' may only be signed with a detached signature. '{fileName.SignInfo.Certificate}' does not produce a detached signature"); } if (fileName.SignInfo.StrongName != null) @@ -564,6 +565,19 @@ private void VerifyCertificates(TaskLoggingHelper log) log.LogError($"Zip {fileName} cannot be strong name signed."); } } + else if (fileName.IsTarGZip()) + { + // Tar.gz files can't be signed without a detached signature. If a certificate is provided but the signature is not detached. + if (!fileName.SignInfo.GeneratesDetachedSignature && fileName.SignInfo.Certificate != null) + { + log.LogError($"'{fileName}' may only be signed with a detached signature. '{fileName.SignInfo.Certificate}' does not produce a detached signature"); + } + + if (fileName.SignInfo.StrongName != null) + { + log.LogError($"TarGZip {fileName} cannot be strong name signed."); + } + } if (fileName.IsExecutableWixContainer()) { if (isInvalidEmptyCertificate) @@ -589,7 +603,28 @@ private void VerifyAfterSign(TaskLoggingHelper log, FileSignInfo file) // No need to check if the file should not have been signed. if (file.SignInfo.ShouldSign) { - if (file.IsPEFile()) + // For files with detached signatures, verify the .sig file exists + if (file.SignInfo.GeneratesDetachedSignature) + { + string sigFilePath = file.DetachedSignatureFullPath; + if (!File.Exists(sigFilePath)) + { + _log.LogError($"Detached signature file {sigFilePath} does not exist for {file.FullPath}"); + } + else + { + var fileInfo = new FileInfo(sigFilePath); + if (fileInfo.Length == 0) + { + _log.LogError($"Detached signature file {sigFilePath} is empty."); + } + else + { + _log.LogMessage(MessageImportance.Low, $"Detached signature file {sigFilePath} exists and is non-empty."); + } + } + } + else if (file.IsPEFile()) { using (var stream = File.OpenRead(file.FullPath)) { diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/Configuration.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/Configuration.cs index 8a48211bb31..1eb5b38408c 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/Configuration.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/Configuration.cs @@ -224,6 +224,14 @@ private FileSignInfo TrackFile(PathWithHash file, PathWithHash parentContainer, // Copy the signed content to the destination path. _filesToCopy.Add(new KeyValuePair(existingSignInfo.FullPath, file.FullPath)); + + // If this is a top-level file that uses detached signatures, also copy the detached signature file + if (existingSignInfo.SignInfo.GeneratesDetachedSignature) + { + _filesToCopy.Add(new KeyValuePair(existingSignInfo.DetachedSignatureFullPath, fileSignInfo.DetachedSignatureFullPath)); + _log.LogMessage(MessageImportance.Low, $"Will copy detached signature from '{existingSignInfo.DetachedSignatureFullPath}' to '{fileSignInfo.DetachedSignatureFullPath}'"); + } + return fileSignInfo; } @@ -262,7 +270,7 @@ private FileSignInfo TrackFile(PathWithHash file, PathWithHash parentContainer, // Only sign containers if the file itself is unsigned, or // an item in the container is unsigned. hasSignableParts = _zipDataMap[fileSignInfo.FileContentKey].NestedParts.Values.Any(b => b.FileSignInfo.SignInfo.ShouldSign || b.FileSignInfo.HasSignableParts); - if(hasSignableParts) + if (hasSignableParts) { // If the file has contents that need to be signed, then re-evaluate the signing info fileSignInfo = fileSignInfo.WithSignableParts(); @@ -529,6 +537,12 @@ private FileSignInfo ExtractSignInfo( Check3rdPartyMicrosoftSignatureMismatch(file, peInfo, signInfo); + // Check if this cert should use detached signatures instead of in-place signing + if (ShouldUseDetachedSignature(file, signInfo)) + { + signInfo = signInfo.WithDetachedSignature(signInfo.Certificate); + } + return new FileSignInfo(file, signInfo, (peInfo != null && peInfo.TargetFramework != "") ? peInfo.TargetFramework : null, wixContentFilePath: wixContentFilePath); } @@ -864,5 +878,27 @@ private bool ShouldSkip3rdPartyCheck(string fileName) { return _itemsToSkip3rdPartyCheck != null && _itemsToSkip3rdPartyCheck.Contains(Path.GetFileName(fileName)); } + + /// + /// Determines if a file should use detached signatures based on certificate configuration. + /// + /// The file to check + /// True if the file should use detached signatures + private bool ShouldUseDetachedSignature(PathWithHash file, SignInfo signInfo) + { + // Check if the certificate is configured for detached signatures + if (signInfo.Certificate != null && _additionalCertificateInformation.TryGetValue(signInfo.Certificate, out var additionalInfo)) + { + var additionalCertInfo = additionalInfo.FirstOrDefault(a => string.IsNullOrEmpty(a.CollisionPriorityId) || + a.CollisionPriorityId == signInfo.CollisionPriorityId); + if (additionalCertInfo != null && additionalCertInfo.GeneratesDetachedSignature) + { + _log.LogMessage(MessageImportance.Low, $"File {file.FileName} will use detached signatures based on certificate configuration"); + return true; + } + } + + return false; + } } } diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/ExplicitCertificateKey.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/ExplicitCertificateKey.cs index b8c775ddb36..14f4531cbcf 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/ExplicitCertificateKey.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/ExplicitCertificateKey.cs @@ -25,20 +25,6 @@ public ExplicitCertificateKey(string fileName, string publicKeyToken = null, str ExecutableType = executableType; } - private static ExecutableType ParseExecutableType(string executableType) - { - if (string.IsNullOrEmpty(executableType)) - return ExecutableType.None; - - return executableType switch - { - "PE" => ExecutableType.PE, - "MachO" => ExecutableType.MachO, - "ELF" => ExecutableType.ELF, - _ => ExecutableType.None - }; - } - public override bool Equals(object obj) => obj is ExplicitCertificateKey key && Equals(key); diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs index 62e5c8636f6..47062c119c6 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs @@ -17,6 +17,9 @@ internal readonly struct FileSignInfo internal readonly SignInfo SignInfo; internal ImmutableArray ContentHash => File.ContentHash; internal readonly string WixContentFilePath; + internal string DetachedSignatureFilePath => $"{FileName}.sig"; + internal string DetachedSignatureFullPath => $"{FullPath}.sig"; + internal readonly PathWithHash File; // optional file information that allows to disambiguate among multiple files with the same name: diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignInfo.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignInfo.cs index a6bb1087218..2f618337432 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignInfo.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignInfo.cs @@ -18,6 +18,11 @@ internal readonly struct SignInfo ///
public static readonly SignInfo AlreadySigned = new SignInfo(ignoreThisFile: false, alreadySigned: true, isAlreadyStrongNamed: false); + /// + /// Used to flag that the file should generate a detached signature. + /// + public static readonly SignInfo DetachedSignature = new SignInfo(ignoreThisFile: false, alreadySigned: false, isAlreadyStrongNamed: false, generatesDetachedSignature: true); + /// /// The authenticode certificate which should be used to sign the binary. This can be null /// in cases where we have a zip container where the contents are signed but not the actual @@ -42,6 +47,11 @@ internal readonly struct SignInfo internal bool IsAlreadySigned { get; } + /// + /// True if this file should generate a detached signature rather than being signed in-place. + /// + internal bool GeneratesDetachedSignature { get; } + /// /// This is used to decide what SignInfos to use in the case of a collision. In case of a collision /// we'll use the lower value since it would map a lower node in the graph and has precedence @@ -57,7 +67,7 @@ internal readonly struct SignInfo public bool ShouldNotarize => !string.IsNullOrEmpty(NotarizationAppName) && !ShouldIgnore; - public SignInfo(string certificate, string strongName, string notarizationAppName, string collisionPriorityId, bool shouldIgnore, bool isAlreadySigned, bool isAlreadyStrongNamed) + private SignInfo(string certificate, string strongName, string notarizationAppName, string collisionPriorityId, bool shouldIgnore, bool isAlreadySigned, bool isAlreadyStrongNamed, bool generatesDetachedSignature = false) { ShouldIgnore = shouldIgnore; IsAlreadySigned = isAlreadySigned; @@ -66,10 +76,11 @@ public SignInfo(string certificate, string strongName, string notarizationAppNam CollisionPriorityId = collisionPriorityId; IsAlreadyStrongNamed = isAlreadyStrongNamed; NotarizationAppName = notarizationAppName; + GeneratesDetachedSignature = generatesDetachedSignature; } - private SignInfo(bool ignoreThisFile, bool alreadySigned, bool isAlreadyStrongNamed) - : this(certificate: null, strongName: null, notarizationAppName: null, collisionPriorityId: null, ignoreThisFile, alreadySigned, isAlreadyStrongNamed) + private SignInfo(bool ignoreThisFile, bool alreadySigned, bool isAlreadyStrongNamed, bool generatesDetachedSignature = false) + : this(certificate: null, strongName: null, notarizationAppName: null, collisionPriorityId: null, ignoreThisFile, alreadySigned, isAlreadyStrongNamed, generatesDetachedSignature) { } @@ -79,20 +90,23 @@ internal SignInfo(string certificate, string strongName = null, string notarizat } internal SignInfo WithCertificateName(string value, string collisionPriorityId) - => new SignInfo(value, StrongName, NotarizationAppName, collisionPriorityId, false, false, IsAlreadyStrongNamed); + => new SignInfo(value, StrongName, NotarizationAppName, collisionPriorityId, false, false, IsAlreadyStrongNamed, GeneratesDetachedSignature); internal SignInfo WithNotarization(string appName, string collisionPriorityId) - => new SignInfo(Certificate, StrongName, appName, collisionPriorityId, false, false, IsAlreadyStrongNamed); + => new SignInfo(Certificate, StrongName, appName, collisionPriorityId, false, false, IsAlreadyStrongNamed, GeneratesDetachedSignature); internal SignInfo WithCollisionPriorityId(string collisionPriorityId) - => new SignInfo(Certificate, StrongName, NotarizationAppName, collisionPriorityId, ShouldIgnore, IsAlreadySigned, IsAlreadyStrongNamed); + => new SignInfo(Certificate, StrongName, NotarizationAppName, collisionPriorityId, ShouldIgnore, IsAlreadySigned, IsAlreadyStrongNamed, GeneratesDetachedSignature); internal SignInfo WithIsAlreadySigned(bool value = false) => Certificate != null ? - new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, value, value, IsAlreadyStrongNamed) : - new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, true, value, IsAlreadyStrongNamed); + new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, value, value, IsAlreadyStrongNamed, GeneratesDetachedSignature) : + new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, true, value, IsAlreadyStrongNamed, GeneratesDetachedSignature); internal SignInfo WithIsAlreadyStrongNamed(bool value = false) => - new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, ShouldIgnore, IsAlreadySigned, value); + new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, ShouldIgnore, IsAlreadySigned, value, GeneratesDetachedSignature); + + internal SignInfo WithDetachedSignature(string certificate) + => new SignInfo(certificate, StrongName, NotarizationAppName, CollisionPriorityId, false, false, IsAlreadyStrongNamed, true); } } diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignTool.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignTool.cs index 6aa74d2ccc1..6b88e6d156b 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignTool.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignTool.cs @@ -13,6 +13,7 @@ using Microsoft.Build.Utilities; using NuGet.Packaging; using Microsoft.DotNet.StrongName; +using System.ComponentModel; namespace Microsoft.DotNet.SignTool { @@ -148,15 +149,37 @@ private bool AuthenticodeSignAndNotarize(IBuildEngine buildEngine, int round, IE var zippedPaths = ZipMacFiles(filesToSign); - // First the signing pass - var signProjectPath = Path.Combine(dir, $"Round{round}-Sign.proj"); - File.WriteAllText(signProjectPath, GenerateBuildFileContent(filesToSign, zippedPaths, false)); - string signingLogName = $"SigningRound{round}"; - status = RunMSBuild(buildEngine, signProjectPath, Path.Combine(_args.LogDir, $"{signingLogName}.binlog"), Path.Combine(_args.LogDir, $"{signingLogName}.log"), Path.Combine(_args.LogDir, $"{signingLogName}.error.log")); + // Identify files that need detached signatures + var detachedSignatureFiles = filesToSign.Where(f => f.SignInfo.GeneratesDetachedSignature).ToList(); + var originalFileBackups = new Dictionary(); - if (!status) + try { - return false; + PrepareDetachedSignatureFiles(detachedSignatureFiles, originalFileBackups); + + var signProjectPath = Path.Combine(dir, $"Round{round}-Sign.proj"); + File.WriteAllText(signProjectPath, GenerateBuildFileContent(filesToSign, zippedPaths, false)); + string signingLogName = $"SigningRound{round}"; + status = RunMSBuild(buildEngine, signProjectPath, Path.Combine(_args.LogDir, $"{signingLogName}.binlog"), Path.Combine(_args.LogDir, $"{signingLogName}.log"), Path.Combine(_args.LogDir, $"{signingLogName}.error.log")); + + if (!status) + { + return false; + } + + // After signing, handle detached signatures + CompleteDetachedSignatures(detachedSignatureFiles, originalFileBackups); + } + finally + { + // Delete any original detached signature files + foreach (var backupPath in originalFileBackups.Values) + { + if (File.Exists(backupPath)) + { + File.Delete(backupPath); + } + } } // Now unzip. Notarization does not expect zipped packages. @@ -175,6 +198,47 @@ private bool AuthenticodeSignAndNotarize(IBuildEngine buildEngine, int round, IE return status; } + /// + /// Copies the signed content to the .sig file and restores the original file. + /// + /// + /// + private void CompleteDetachedSignatures(List detachedSignatureFiles, Dictionary originalFileBackups) + { + foreach (var fileInfo in detachedSignatureFiles) + { + // Copy the signed content to .sig file + File.Copy(fileInfo.FullPath, fileInfo.DetachedSignatureFullPath); + _log.LogMessage($"Created detached signature file: {fileInfo.DetachedSignatureFullPath}"); + + // Restore the original file + string backupPath = originalFileBackups[fileInfo.FullPath]; + File.Copy(backupPath, fileInfo.FullPath, overwrite: true); + _log.LogMessage($"Restored original file: {fileInfo.FullPath}"); + } + } + + /// + /// Creates backup copies of the specified files to prepare for detached signature operations. + /// + /// Each file is backed up by copying it to a new file with the ".original" extension + /// appended to its path. The method updates the provided dictionary to allow later restoration of the original + /// files if needed. + /// A list of file information objects representing the files for which detached signature backups will be + /// created. Each file in the list will be copied to a backup location. + /// A dictionary that will be populated with mappings from the original file paths to their corresponding backup + /// file paths. The dictionary is updated in place. + private void PrepareDetachedSignatureFiles(List detachedSignatureFiles, Dictionary originalFileBackups) + { + foreach (var fileInfo in detachedSignatureFiles) + { + string backupPath = fileInfo.FullPath + ".original"; + File.Copy(fileInfo.FullPath, backupPath); + originalFileBackups[fileInfo.FullPath] = backupPath; + _log.LogMessage($"Backed up original file for detached signature: {fileInfo.FullPath} -> {backupPath}"); + } + } + private string GenerateBuildFileContent(IEnumerable filesToSign, Dictionary zippedPaths, bool notarize) { var builder = new StringBuilder(); diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignToolTask.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignToolTask.cs index b999bbd6502..14d65f5bf0f 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignToolTask.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignToolTask.cs @@ -336,6 +336,8 @@ private Dictionary> ParseAddition var macSigningOperation = certificateSignInfo.GetMetadata("MacCertificate"); var macNotarizationAppName = certificateSignInfo.GetMetadata("MacNotarizationAppName"); var collisionPriorityId = certificateSignInfo.GetMetadata(SignToolConstants.CollisionPriorityId); + var detachedSignatureCertificate = certificateSignInfo.GetMetadata("DetachedSignature"); + bool detachedSignatureCertificateValue = false; if (string.IsNullOrEmpty(macSigningOperation) != string.IsNullOrEmpty(macNotarizationAppName)) { @@ -348,11 +350,18 @@ private Dictionary> ParseAddition continue; } + if (!string.IsNullOrEmpty(detachedSignatureCertificate) && !bool.TryParse(detachedSignatureCertificate, out detachedSignatureCertificateValue)) + { + Log.LogError($"DetachedSignature must be 'true' or 'false"); + continue; + } + var additionalCertInfo = new AdditionalCertificateInformation { DualSigningAllowed = dualSignAllowedValue, MacSigningOperation = macSigningOperation, MacNotarizationAppName = macNotarizationAppName, + GeneratesDetachedSignature = detachedSignatureCertificateValue, CollisionPriorityId = collisionPriorityId }; diff --git a/src/source-manifest.json b/src/source-manifest.json index 7a1e827cf9b..a266a4b027a 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -1,10 +1,10 @@ { "repositories": [ { - "barId": 285108, + "barId": 286215, "path": "arcade", "remoteUri": "https://github.com/dotnet/arcade", - "commitSha": "e6f510cb87812d56ad781d93ff0513cdcccd0eb4" + "commitSha": "7ff6478d902606d65aa33cb8cedc2730e1843fe1" }, { "barId": 286219, From 8656e755a6efd273c038b670bc52648783d3f667 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 08:51:29 +0000 Subject: [PATCH 13/28] [release/10.0.1xx] Source code updates from nuget/nuget.client (#2819) [release/10.0.1xx] Source code updates from nuget/nuget.client --- .../build/DotNetSdkTestVersions.txt | 2 +- src/nuget-client/build/common.project.props | 2 - src/nuget-client/build/common.targets | 2 +- src/nuget-client/build/config.props | 2 +- src/nuget-client/eng/Version.Details.props | 4 +- src/nuget-client/eng/Version.Details.xml | 10 +-- .../eng/common/SetupNugetSources.ps1 | 2 +- .../eng/common/SetupNugetSources.sh | 2 +- .../job/publish-build-assets.yml | 9 ++- .../eng/common/core-templates/jobs/jobs.yml | 2 + .../steps/source-index-stage1-publish.yml | 4 +- .../common/post-build/nuget-verification.ps1 | 2 +- src/nuget-client/eng/common/sdk-task.ps1 | 3 +- src/nuget-client/eng/common/sdk-task.sh | 7 +- src/nuget-client/eng/common/tools.ps1 | 2 +- src/nuget-client/eng/pipelines/optprof.yml | 1 + .../eng/pipelines/templates/pipeline.yml | 2 +- src/nuget-client/global.json | 2 +- .../Models/DetailControlModel.cs | 9 ++- .../Models/DetailedPackageMetadata.cs | 6 +- .../Models/Package/PackageModelFactory.cs | 6 +- .../NuGetSourcesServiceWrapper.cs | 8 +++ .../ViewModels/PackageItemViewModel.cs | 2 +- .../Xamls/PackageManagerControl.xaml.cs | 14 +++- .../Services/NuGetSourcesService.cs | 20 ++++++ .../Services/PackageVulnerabilityService.cs | 69 ++++++++++++++----- .../NuGet.VisualStudio.Client/mcp.json | 2 +- .../INuGetSourcesService.cs | 3 + .../Update/PackageUpdateCommandRunner.cs | 20 +++--- .../Package/Update/PackageUpdateIO.cs | 7 +- .../PublicAPI.Shipped.txt | 3 + .../PublicAPI.Unshipped.txt | 3 - .../PublicAPI/net472/PublicAPI.Shipped.txt | 16 +++++ .../PublicAPI/net472/PublicAPI.Unshipped.txt | 16 ----- .../PublicAPI/net8.0/PublicAPI.Shipped.txt | 16 +++++ .../PublicAPI/net8.0/PublicAPI.Unshipped.txt | 16 ----- .../netstandard2.0/PublicAPI.Shipped.txt | 16 +++++ .../netstandard2.0/PublicAPI.Unshipped.txt | 16 ----- .../NuGet.Common/PublicAPI.Shipped.txt | 3 + .../NuGet.Common/PublicAPI.Unshipped.txt | 3 - .../PublicAPI.Shipped.txt | 1 + .../PublicAPI.Unshipped.txt | 1 - .../PublicAPI/net472/PublicAPI.Shipped.txt | 2 + .../PublicAPI/net472/PublicAPI.Unshipped.txt | 2 - .../PublicAPI/net8.0/PublicAPI.Shipped.txt | 2 + .../PublicAPI/net8.0/PublicAPI.Unshipped.txt | 2 - .../NuGet.ProjectModel/PublicAPI.Shipped.txt | 11 ++- .../PublicAPI.Unshipped.txt | 9 --- .../PublicAPI/net472/PublicAPI.Shipped.txt | 3 + .../PublicAPI/net472/PublicAPI.Unshipped.txt | 3 - .../PublicAPI/net8.0/PublicAPI.Shipped.txt | 3 + .../PublicAPI/net8.0/PublicAPI.Unshipped.txt | 3 - .../netstandard2.0/PublicAPI.Shipped.txt | 3 + .../netstandard2.0/PublicAPI.Unshipped.txt | 3 - .../Models/DetailedPackageMetadataTests.cs | 2 +- .../NuGetSourcesServiceWrapperTests.cs | 6 ++ .../PackageVulnerabilityServiceTests.cs | 67 ++++++++++++++++-- .../DotnetPackageUpdateTests.cs | 60 ++++++++++++++++ .../MultiProjectTests.cs | 6 +- src/source-manifest.json | 4 +- 60 files changed, 368 insertions(+), 159 deletions(-) diff --git a/src/nuget-client/build/DotNetSdkTestVersions.txt b/src/nuget-client/build/DotNetSdkTestVersions.txt index 041f89b91b4..d4a2109c8e2 100644 --- a/src/nuget-client/build/DotNetSdkTestVersions.txt +++ b/src/nuget-client/build/DotNetSdkTestVersions.txt @@ -2,4 +2,4 @@ # To make sure that the right version of dotnet.exe (and maybe other files) is used, always install from lowest version to highest version -Channel 8.0 -Runtime dotnet -Channel 9.0 -Runtime dotnet --Channel 10.0.1xx -Version 10.0.100-rc.2.25465.104 +-Channel 10.0.1xx -Quality daily diff --git a/src/nuget-client/build/common.project.props b/src/nuget-client/build/common.project.props index 5f7af2d3650..ab90d04409a 100644 --- a/src/nuget-client/build/common.project.props +++ b/src/nuget-client/build/common.project.props @@ -142,8 +142,6 @@ - $(SemanticVersion).$(PreReleaseVersion) - $(SemanticVersion).0 $(SemanticVersion).$(PreReleaseVersion) $(SemanticVersion)$(PreReleaseInformationVersion) $(SemanticVersion)$(PreReleaseInformationVersion)+$(BUILD_SOURCEVERSION) diff --git a/src/nuget-client/build/common.targets b/src/nuget-client/build/common.targets index b0ea719307b..14934090e62 100644 --- a/src/nuget-client/build/common.targets +++ b/src/nuget-client/build/common.targets @@ -2,7 +2,7 @@ - + $(SemanticVersion).$(PreReleaseVersion) $(SemanticVersion).0 diff --git a/src/nuget-client/build/config.props b/src/nuget-client/build/config.props index 83fcdc328ce..26e1ba81e9b 100644 --- a/src/nuget-client/build/config.props +++ b/src/nuget-client/build/config.props @@ -22,7 +22,7 @@ rc - false + true $([MSBuild]::Add(11, $(MajorNuGetVersion))) diff --git a/src/nuget-client/eng/Version.Details.props b/src/nuget-client/eng/Version.Details.props index 02eb28a0001..1092349c1de 100644 --- a/src/nuget-client/eng/Version.Details.props +++ b/src/nuget-client/eng/Version.Details.props @@ -21,8 +21,8 @@ This file should be imported by eng/Versions.props 4.5.0 - 10.0.0-beta.25420.109 - 10.0.0-beta.25420.109 + 10.0.0-beta.25468.104 + 10.0.0-beta.25468.104 diff --git a/src/nuget-client/eng/Version.Details.xml b/src/nuget-client/eng/Version.Details.xml index 90dcf3571a7..328e46c38da 100644 --- a/src/nuget-client/eng/Version.Details.xml +++ b/src/nuget-client/eng/Version.Details.xml @@ -1,6 +1,6 @@ - + - 2.0.0-rtm.25507.103 + 2.0.0-rtm.25509.106 9.0.0 9.0.0 diff --git a/src/roslyn/eng/Version.Details.xml b/src/roslyn/eng/Version.Details.xml index 79cd3e0eec7..bf9bdd564bc 100644 --- a/src/roslyn/eng/Version.Details.xml +++ b/src/roslyn/eng/Version.Details.xml @@ -1,15 +1,15 @@ - + https://github.com/dotnet/roslyn ae1fff344d46976624e68ae17164e0607ab68b10 - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac diff --git a/src/roslyn/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.cs b/src/roslyn/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.cs index bb6dc5aecab..2c98eac46a0 100644 --- a/src/roslyn/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.cs +++ b/src/roslyn/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.cs @@ -4640,5 +4640,17 @@ void M() Assert.Same(analyzer1.SeenOptions, analyzer2.SeenOptions); } } + + [Fact] + public async Task TestGetAnalysisResultAsyncWithUnknownAnalyzerThrows() + { + var compilation = CreateCompilation("").VerifyDiagnostics(); + + var compilationWithAnalyzers = compilation.WithAnalyzers([new CSharpCompilerDiagnosticAnalyzer()]); + + // Calling with a DiagnosticAnalyzer that was not specified in 'WithAnalyzers' should throw. + await Assert.ThrowsAnyAsync(() => + compilationWithAnalyzers.GetAnalysisResultAsync([new CSharpCompilerDiagnosticAnalyzer()], CancellationToken.None)); + } } } diff --git a/src/roslyn/src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs b/src/roslyn/src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs index 3a7a679a1ab..19f59d0bd4f 100644 --- a/src/roslyn/src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs +++ b/src/roslyn/src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs @@ -1590,6 +1590,61 @@ internal class TestAttribute : Attribute Assert.Equal(DiagnosticSuppressorForCS0657.SuppressionId, suppression.Descriptor.Id); } + [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2581061")] + public async Task TestDiagnosticSuppressor_GetAnalysisResultAsyncCrash() + { + var source = """ + using System; + + public class SomeClass + { + [property: Test] + public string Name; + } + + internal class TestAttribute : Attribute + { + } + """; + var compilation = CreateCompilation(source).VerifyDiagnostics( + // (5,6): warning CS0657: 'property' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'field'. All attributes in this block will be ignored. + // [property: Test] + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "property").WithArguments("property", "field").WithLocation(5, 6)); + + // Verify that CS0657 can be suppressed with a DiagnosticSuppressor + var diagnosticAnalyzer = new CSharpCompilerDiagnosticAnalyzer(); + var suppressor = new DiagnosticSuppressorForCS0657(); + + // Create options with our own getAnalyzerConfigOptionsProvider. That way we do initialize the map from + // analyzer to options within the AnalyzerDriver. This map needs to contain all analyzers and suppressors, + // not just the one we're calling into with GetAnalysisResultAsync. + var options = new CompilationWithAnalyzersOptions( + AnalyzerOptions.Empty, + onAnalyzerException: null, + concurrentAnalysis: false, + logAnalyzerExecutionTime: false, + reportSuppressedDiagnostics: true, + analyzerExceptionFilter: null, + getAnalyzerConfigOptionsProvider: _ => new CompilerAnalyzerConfigOptionsProvider( + ImmutableDictionary.Empty, + new DictionaryAnalyzerConfigOptions(ImmutableDictionary.Empty))); + + var compilationWithAnalyzers = compilation.WithAnalyzers([diagnosticAnalyzer, suppressor], options); + + // Calling in with a single analyzer should still properly setup internal maps so that suppressors run properly. + var analysisResult1 = await compilationWithAnalyzers.GetAnalysisResultAsync([diagnosticAnalyzer], CancellationToken.None); + var analysisResult2 = await compilationWithAnalyzers.GetAnalysisResultAsync([diagnosticAnalyzer, suppressor], CancellationToken.None); + + var diagnostic1 = analysisResult1.SemanticDiagnostics.Single().Value.Single().Value.Single(); + var diagnostic2 = analysisResult2.SemanticDiagnostics.Single().Value.Single().Value.Single(); + + Assert.True(diagnostic1.IsSuppressed); + Assert.True(diagnostic2.IsSuppressed); + + Assert.Equal("CS0657", diagnostic1.Id); + Assert.Equal("CS0657", diagnostic2.Id); + } + [DiagnosticAnalyzer(LanguageNames.CSharp)] private sealed class DiagnosticSuppressorForCS0657 : DiagnosticSuppressor { diff --git a/src/roslyn/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs b/src/roslyn/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs index 385e075a73c..134ee76bc9d 100644 --- a/src/roslyn/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs +++ b/src/roslyn/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs @@ -518,7 +518,7 @@ internal void Initialize( var analyzerExecutor = AnalyzerExecutor.Create( compilation, options, addNotCategorizedDiagnostic, newOnAnalyzerException, analysisOptions.AnalyzerExceptionFilter, - IsCompilerAnalyzer, analysisScope.Analyzers, analysisOptions.GetAnalyzerConfigOptionsProvider, + IsCompilerAnalyzer, this.Analyzers, analysisOptions.GetAnalyzerConfigOptionsProvider, AnalyzerManager, ShouldSkipAnalysisOnGeneratedCode, ShouldSuppressGeneratedCodeDiagnostic, IsGeneratedOrHiddenCodeLocation, IsAnalyzerSuppressedForTree, GetAnalyzerGate, getSemanticModel: GetOrCreateSemanticModel, _severityFilter, analysisOptions.LogAnalyzerExecutionTime, addCategorizedLocalDiagnostic, addCategorizedNonLocalDiagnostic, s => _programmaticSuppressions!.Add(s)); diff --git a/src/source-manifest.json b/src/source-manifest.json index 18fc39b99a8..d0ba0dac43e 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -73,10 +73,10 @@ "commitSha": "99f4851d332b95b81064facb5a6647683efb61f5" }, { - "barId": 286121, + "barId": 286456, "path": "roslyn", "remoteUri": "https://github.com/dotnet/roslyn", - "commitSha": "23d275e30097136b12a68d1bab4997148361d116" + "commitSha": "929ae2333a73eca047b9b6e2f01bf7121558308f" }, { "barId": 286218, From 982d1b7b4e3a846aa504138108e89494b841e69a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 12:38:55 +0000 Subject: [PATCH 16/28] [release/10.0.1xx] Source code updates from dotnet/efcore (#2818) [release/10.0.1xx] Source code updates from dotnet/efcore --- src/efcore/eng/Version.Details.props | 36 ++++----- src/efcore/eng/Version.Details.xml | 74 +++++++++---------- src/efcore/global.json | 4 +- .../Internal/RelationalParameterProcessor.cs | 2 +- .../Query/NorthwindWhereQueryCosmosTest.cs | 38 ++++++++-- .../Query/NorthwindWhereQueryTestBase.cs | 19 ++++- .../Query/NorthwindWhereQuerySqlServerTest.cs | 22 +++++- src/source-manifest.json | 4 +- 8 files changed, 125 insertions(+), 74 deletions(-) diff --git a/src/efcore/eng/Version.Details.props b/src/efcore/eng/Version.Details.props index 0549f6aee01..70ce7292d37 100644 --- a/src/efcore/eng/Version.Details.props +++ b/src/efcore/eng/Version.Details.props @@ -6,24 +6,24 @@ This file should be imported by eng/Versions.props - 10.0.0-beta.25479.115 - 10.0.0-beta.25479.115 - 10.0.0-beta.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 - 10.0.0-rtm.25479.115 + 10.0.0-beta.25507.103 + 10.0.0-beta.25507.103 + 10.0.0-beta.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 + 10.0.0-rtm.25507.103 diff --git a/src/efcore/eng/Version.Details.xml b/src/efcore/eng/Version.Details.xml index cda2ae34f9c..d04c92e1960 100644 --- a/src/efcore/eng/Version.Details.xml +++ b/src/efcore/eng/Version.Details.xml @@ -1,80 +1,80 @@ - + - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 - + https://github.com/dotnet/dotnet - e72b5bbe719d747036ce9c36582a205df9f1c361 + 915977521b41280adbe21a54345be23cb5bf3536 diff --git a/src/efcore/global.json b/src/efcore/global.json index 7576fe190a4..dffd3048bc8 100644 --- a/src/efcore/global.json +++ b/src/efcore/global.json @@ -18,7 +18,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25479.115", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25479.115" + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25507.103", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25507.103" } } diff --git a/src/efcore/src/EFCore.Relational/Query/Internal/RelationalParameterProcessor.cs b/src/efcore/src/EFCore.Relational/Query/Internal/RelationalParameterProcessor.cs index 392a94f28a9..433b0b317c1 100644 --- a/src/efcore/src/EFCore.Relational/Query/Internal/RelationalParameterProcessor.cs +++ b/src/efcore/src/EFCore.Relational/Query/Internal/RelationalParameterProcessor.cs @@ -31,7 +31,7 @@ private readonly IDictionary _visitedFromSqlExpre /// (i.e. they're prefixed), since /// can be prefixed or not. /// - private readonly HashSet _prefixedParameterNames = []; + private readonly HashSet _prefixedParameterNames = new(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _sqlParameters = new(); diff --git a/src/efcore/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs b/src/efcore/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs index 8d066cc59e5..f91ad1dee97 100644 --- a/src/efcore/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs +++ b/src/efcore/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs @@ -1529,13 +1529,39 @@ public override async Task Using_same_parameter_twice_in_query_generates_one_sql AssertSql(); } - public override async Task Two_parameters_with_same_name_get_uniquified(bool async) - { - // Concat with conversion, issue #34963. - await AssertTranslationFailed(() => base.Using_same_parameter_twice_in_query_generates_one_sql_parameter(async)); + public override Task Two_parameters_with_same_name_get_uniquified(bool async) + => Fixture.NoSyncTest( + async, async a => + { + await base.Two_parameters_with_same_name_get_uniquified(async); - AssertSql(); - } + AssertSql( + """ +@customerId='ANATR' +@customerId0='ALFKI' + +SELECT VALUE c +FROM root c +WHERE ((c["id"] = @customerId) OR (c["id"] = @customerId0)) +"""); + }); + + public override Task Two_parameters_with_same_case_insensitive_name_get_uniquified(bool async) + => Fixture.NoSyncTest( + async, async a => + { + await base.Two_parameters_with_same_case_insensitive_name_get_uniquified(async); + + AssertSql( + """ +@customerID='ANATR' +@customerId='ALFKI' + +SELECT VALUE c +FROM root c +WHERE ((c["id"] = @customerID) OR (c["id"] = @customerId)) +"""); + }); public override async Task Where_Queryable_ToList_Count(bool async) { diff --git a/src/efcore/test/EFCore.Specification.Tests/Query/NorthwindWhereQueryTestBase.cs b/src/efcore/test/EFCore.Specification.Tests/Query/NorthwindWhereQueryTestBase.cs index 69c990d6845..e4beae2c27e 100644 --- a/src/efcore/test/EFCore.Specification.Tests/Query/NorthwindWhereQueryTestBase.cs +++ b/src/efcore/test/EFCore.Specification.Tests/Query/NorthwindWhereQueryTestBase.cs @@ -1327,16 +1327,27 @@ public virtual Task Using_same_parameter_twice_in_query_generates_one_sql_parame .Select(c => c.CustomerID)); } + private readonly string customerId = "ALFKI"; + [ConditionalTheory, MemberData(nameof(IsAsyncData))] public virtual Task Two_parameters_with_same_name_get_uniquified(bool async) { - var i = 10; + var customerId = "ANATR"; + + return AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID == customerId || c.CustomerID == this.customerId)); + } + + [ConditionalTheory, MemberData(nameof(IsAsyncData))] + public virtual Task Two_parameters_with_same_case_insensitive_name_get_uniquified(bool async) + { + var customerID = "ANATR"; - // i+1 and i+2 each get parameterized using the same parameter name (since they're complex expressions). - // This exercises that query parameters are properly uniquified. + // Note the parameter names differ only by case (customerID vs. customerId) return AssertQuery( async, - ss => ss.Set().Where(c => (c.CustomerID + (i + 1)) + (c.CustomerID + (i + 2)) == "ALFKI11ALFKI12")); + ss => ss.Set().Where(c => c.CustomerID == customerID || c.CustomerID == customerId)); } [ConditionalTheory, MemberData(nameof(IsAsyncData))] diff --git a/src/efcore/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs b/src/efcore/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs index bd0137646c4..63a234e7e7c 100644 --- a/src/efcore/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs +++ b/src/efcore/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs @@ -1704,19 +1704,33 @@ WHERE CAST(@i AS nvarchar(max)) + [c].[CustomerID] + CAST(@i AS nvarchar(max)) = """); } - [ConditionalTheory] public override async Task Two_parameters_with_same_name_get_uniquified(bool async) { await base.Two_parameters_with_same_name_get_uniquified(async); AssertSql( """ -@p='11' -@p0='12' +@customerId='ANATR' (Size = 5) (DbType = StringFixedLength) +@customerId0='ALFKI' (Size = 5) (DbType = StringFixedLength) + +SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE [c].[CustomerID] = @customerId OR [c].[CustomerID] = @customerId0 +"""); + } + + public override async Task Two_parameters_with_same_case_insensitive_name_get_uniquified(bool async) + { + await base.Two_parameters_with_same_case_insensitive_name_get_uniquified(async); + +AssertSql( +""" +@customerID='ANATR' (Size = 5) (DbType = StringFixedLength) +@customerId0='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] + CAST(@p AS nvarchar(max)) + [c].[CustomerID] + CAST(@p0 AS nvarchar(max)) = N'ALFKI11ALFKI12' +WHERE [c].[CustomerID] = @customerID OR [c].[CustomerID] = @customerId0 """); } diff --git a/src/source-manifest.json b/src/source-manifest.json index d0ba0dac43e..fce1fec6cdc 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -37,10 +37,10 @@ "commitSha": "f40e210b5da69e3c7585917137322cac01f0dffc" }, { - "barId": 285648, + "barId": 286443, "path": "efcore", "remoteUri": "https://github.com/dotnet/efcore", - "commitSha": "9f21708d124ca38c7d2c94d5538b597ba20129e1" + "commitSha": "5457b1b858107bd3a0412810b7c665052df29b56" }, { "barId": 283436, From d7c12f23ffab6e380f5f5e5dddb55cbf4a9b287e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 12:40:13 +0000 Subject: [PATCH 17/28] [release/10.0.1xx] Source code updates from dotnet/templating (#2823) [release/10.0.1xx] Source code updates from dotnet/templating --- src/source-manifest.json | 4 ++-- src/templating/.editorconfig | 7 +++++++ src/templating/eng/Version.Details.props | 4 ++-- src/templating/eng/Version.Details.xml | 10 +++++----- .../eng/common/core-templates/job/source-build.yml | 4 ++++ .../common/core-templates/jobs/source-build.yml | 5 +++++ .../common/core-templates/steps/source-build.yml | 4 ++++ src/templating/global.json | 2 +- .../Components/IBindSymbolSource.cs | 8 ++++---- .../Components/ISdkInfoProvider.cs | 6 +++--- .../Components/IWorkloadsInfoProvider.cs | 4 ++-- .../IValidationEntry.cs | 4 ++-- .../Abstractions/ITemplatePackageInfo.cs | 14 +++++++------- 13 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/source-manifest.json b/src/source-manifest.json index fce1fec6cdc..df15f47008c 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -115,10 +115,10 @@ "commitSha": "26c6c313a35f020dc9fa8c7270a012bcd75fc81b" }, { - "barId": 285272, + "barId": 286484, "path": "templating", "remoteUri": "https://github.com/dotnet/templating", - "commitSha": "4c36907d7149f0b3b59c7178acea6330540df851" + "commitSha": "89fd90b5b2016cff0ee924dca2c8bf71b4935a39" }, { "barId": 285355, diff --git a/src/templating/.editorconfig b/src/templating/.editorconfig index bc46cb200f8..178d2855e1c 100644 --- a/src/templating/.editorconfig +++ b/src/templating/.editorconfig @@ -186,10 +186,14 @@ dotnet_code_quality.ca1822.api_surface = private, internal dotnet_code_quality.ca2208.api_surface = public dotnet_diagnostic.CS1591.severity = suggestion dotnet_analyzer_diagnostic.category-Style.severity = warning +#Name can be simplified +dotnet_diagnostic.IDE0002.severity = suggestion #Use explicit type instead of var dotnet_diagnostic.IDE0008.severity = suggestion #Add missing cases to switch statement dotnet_diagnostic.IDE0010.severity = suggestion +#Simplify LINQ expression +dotnet_diagnostic.IDE0120.severity = suggestion #Use expression body for constructors dotnet_diagnostic.IDE0021.severity = suggestion #Use expression body for methods @@ -235,6 +239,9 @@ file_header_template = Licensed to the .NET Foundation under one or more agreeme # Ensure minimum API surface is respected dotnet_diagnostic.BCL0001.severity = warning +# Don't require explicit access modifiers for interface members (conflicts with IDE0040) +dotnet_diagnostic.SA1400.severity = none + # AppContext default value expected to be true dotnet_diagnostic.BCL0010.severity = warning diff --git a/src/templating/eng/Version.Details.props b/src/templating/eng/Version.Details.props index 9c9fabfbbc0..1653acc7903 100644 --- a/src/templating/eng/Version.Details.props +++ b/src/templating/eng/Version.Details.props @@ -6,8 +6,8 @@ This file should be imported by eng/Versions.props - 10.0.0-beta.25479.109 - 2.0.0-rtm.25479.109 + 10.0.0-beta.25509.106 + 2.0.0-rtm.25509.106 9.0.3 9.0.3 diff --git a/src/templating/eng/Version.Details.xml b/src/templating/eng/Version.Details.xml index a28e2082ff6..cdaccc6842f 100644 --- a/src/templating/eng/Version.Details.xml +++ b/src/templating/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + - + https://github.com/dotnet/dotnet - 8aba88f6f12f3ce1dd5740575cff9442f1f9122c + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 8aba88f6f12f3ce1dd5740575cff9442f1f9122c + f448387a0e80f2fdeaec2d2f99ace7284fe37aac diff --git a/src/templating/eng/common/core-templates/job/source-build.yml b/src/templating/eng/common/core-templates/job/source-build.yml index d805d5faeb9..947f0971eb5 100644 --- a/src/templating/eng/common/core-templates/job/source-build.yml +++ b/src/templating/eng/common/core-templates/job/source-build.yml @@ -34,6 +34,9 @@ parameters: # container and pool. platform: {} + # Optional list of directories to ignore for component governance scans. + componentGovernanceIgnoreDirectories: [] + is1ESPipeline: '' # If set to true and running on a non-public project, @@ -94,3 +97,4 @@ jobs: parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} platform: ${{ parameters.platform }} + componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} diff --git a/src/templating/eng/common/core-templates/jobs/source-build.yml b/src/templating/eng/common/core-templates/jobs/source-build.yml index d92860cba20..eb4b923a777 100644 --- a/src/templating/eng/common/core-templates/jobs/source-build.yml +++ b/src/templating/eng/common/core-templates/jobs/source-build.yml @@ -15,6 +15,9 @@ parameters: # one job runs on 'defaultManagedPlatform'. platforms: [] + # Optional list of directories to ignore for component governance scans. + componentGovernanceIgnoreDirectories: [] + is1ESPipeline: '' # If set to true and running on a non-public project, @@ -31,6 +34,7 @@ jobs: is1ESPipeline: ${{ parameters.is1ESPipeline }} jobNamePrefix: ${{ parameters.jobNamePrefix }} platform: ${{ platform }} + componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} enableInternalSources: ${{ parameters.enableInternalSources }} - ${{ if eq(length(parameters.platforms), 0) }}: @@ -39,4 +43,5 @@ jobs: is1ESPipeline: ${{ parameters.is1ESPipeline }} jobNamePrefix: ${{ parameters.jobNamePrefix }} platform: ${{ parameters.defaultManagedPlatform }} + componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} enableInternalSources: ${{ parameters.enableInternalSources }} diff --git a/src/templating/eng/common/core-templates/steps/source-build.yml b/src/templating/eng/common/core-templates/steps/source-build.yml index acf16ed3496..77321eee11f 100644 --- a/src/templating/eng/common/core-templates/steps/source-build.yml +++ b/src/templating/eng/common/core-templates/steps/source-build.yml @@ -11,6 +11,10 @@ parameters: # for details. The entire object is described in the 'job' template for simplicity, even though # the usage of the properties on this object is split between the 'job' and 'steps' templates. platform: {} + + # Optional list of directories to ignore for component governance scans. + componentGovernanceIgnoreDirectories: [] + is1ESPipeline: false steps: diff --git a/src/templating/global.json b/src/templating/global.json index 2601ff58bf9..7d699a3dfc6 100644 --- a/src/templating/global.json +++ b/src/templating/global.json @@ -13,6 +13,6 @@ "dotnet": "10.0.100-rc.1.25451.107" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25479.109" + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25509.106" } } diff --git a/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/IBindSymbolSource.cs b/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/IBindSymbolSource.cs index faacc3ef1da..beeefddb72f 100644 --- a/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/IBindSymbolSource.cs +++ b/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/IBindSymbolSource.cs @@ -12,17 +12,17 @@ public interface IBindSymbolSource : IPrioritizedComponent /// /// The user friendly name of the component. /// - public string DisplayName { get; } + string DisplayName { get; } /// /// Prefix that is used in binding to reference the component. /// - public string? SourcePrefix { get; } + string? SourcePrefix { get; } /// /// If set to true, the component required exact prefix match to be used. /// - public bool RequiresPrefixMatch { get; } + bool RequiresPrefixMatch { get; } /// /// Gets the value corresponding to . @@ -31,6 +31,6 @@ public interface IBindSymbolSource : IPrioritizedComponent /// the value to retrieve (without prefix). /// cancellation token. /// - public Task GetBoundValueAsync(IEngineEnvironmentSettings settings, string bindName, CancellationToken cancellationToken); + Task GetBoundValueAsync(IEngineEnvironmentSettings settings, string bindName, CancellationToken cancellationToken); } } diff --git a/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/ISdkInfoProvider.cs b/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/ISdkInfoProvider.cs index 7074e49488b..ebe85225cee 100644 --- a/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/ISdkInfoProvider.cs +++ b/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/ISdkInfoProvider.cs @@ -13,14 +13,14 @@ public interface ISdkInfoProvider : IIdentifiedComponent /// /// /// SDK version. - public Task GetCurrentVersionAsync(CancellationToken cancellationToken); + Task GetCurrentVersionAsync(CancellationToken cancellationToken); /// /// All installed SDK installations semver version strings. /// /// /// SDK version strings. - public Task> GetInstalledVersionsAsync(CancellationToken cancellationToken); + Task> GetInstalledVersionsAsync(CancellationToken cancellationToken); /// /// Provides localized suggestion on action to be taken so that constraints requiring specified workloads can be met. @@ -31,6 +31,6 @@ public interface ISdkInfoProvider : IIdentifiedComponent /// SDK versions required by a constraint (in an 'OR' relationship). /// SDK versions installed, that can meet the constraint - instructions should be provided to switch to any of those. /// Localized string with remedy suggestion specific to current host. - public string ProvideConstraintRemedySuggestion(IReadOnlyList supportedVersions, IReadOnlyList viableInstalledVersions); + string ProvideConstraintRemedySuggestion(IReadOnlyList supportedVersions, IReadOnlyList viableInstalledVersions); } } diff --git a/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/IWorkloadsInfoProvider.cs b/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/IWorkloadsInfoProvider.cs index 8aeb8ae4317..9e512c4e163 100644 --- a/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/IWorkloadsInfoProvider.cs +++ b/src/templating/src/Microsoft.TemplateEngine.Abstractions/Components/IWorkloadsInfoProvider.cs @@ -13,7 +13,7 @@ public interface IWorkloadsInfoProvider : IIdentifiedComponent /// /// /// Set of installed workloads. - public Task> GetInstalledWorkloadsAsync(CancellationToken token); + Task> GetInstalledWorkloadsAsync(CancellationToken token); /// /// Provides localized suggestion on action to be taken so that constraints requiring specified workloads can be met. @@ -23,6 +23,6 @@ public interface IWorkloadsInfoProvider : IIdentifiedComponent /// /// Workloads required by a constraint (in an 'OR' relationship). /// Localized string with remedy suggestion specific to current host. - public string ProvideConstraintRemedySuggestion(IReadOnlyList supportedWorkloads); + string ProvideConstraintRemedySuggestion(IReadOnlyList supportedWorkloads); } } diff --git a/src/templating/src/Microsoft.TemplateEngine.Abstractions/IValidationEntry.cs b/src/templating/src/Microsoft.TemplateEngine.Abstractions/IValidationEntry.cs index 30bacbccb2c..f82b0ecf6c9 100644 --- a/src/templating/src/Microsoft.TemplateEngine.Abstractions/IValidationEntry.cs +++ b/src/templating/src/Microsoft.TemplateEngine.Abstractions/IValidationEntry.cs @@ -11,7 +11,7 @@ public interface IValidationEntry /// /// Error severity. /// - public enum SeverityLevel + enum SeverityLevel { None, Info, @@ -42,7 +42,7 @@ public enum SeverityLevel /// /// Details of the error location. /// - public readonly struct ErrorLocation + readonly struct ErrorLocation { /// /// Gets the filename where the error occurred. diff --git a/src/templating/src/Microsoft.TemplateSearch.Common/Abstractions/ITemplatePackageInfo.cs b/src/templating/src/Microsoft.TemplateSearch.Common/Abstractions/ITemplatePackageInfo.cs index 2654dad250a..0b523ec8bce 100644 --- a/src/templating/src/Microsoft.TemplateSearch.Common/Abstractions/ITemplatePackageInfo.cs +++ b/src/templating/src/Microsoft.TemplateSearch.Common/Abstractions/ITemplatePackageInfo.cs @@ -11,23 +11,23 @@ public interface ITemplatePackageInfo /// /// Gets template package name. /// - public string Name { get; } + string Name { get; } /// /// Gets template package version. /// - public string? Version { get; } + string? Version { get; } /// /// Gets total number of downloads for the package. /// Optional, might be 0 in case search provider cannot provide number of downloads. /// - public long TotalDownloads { get; } + long TotalDownloads { get; } /// /// Gets the list of template package owners. /// - public IReadOnlyList Owners { get; } + IReadOnlyList Owners { get; } /// /// Gets the indication if the package is verified. @@ -35,16 +35,16 @@ public interface ITemplatePackageInfo /// /// For NuGet.org 'verified' means that package ID is under reserved namespaces, see . /// - public bool Reserved { get; } + bool Reserved { get; } /// /// Gets the NuGet package description. /// - public string? Description { get; } + string? Description { get; } /// /// Gets the URL to the package icon. /// - public string? IconUrl { get; } + string? IconUrl { get; } } } From a45256fdc7c1a6cac28f28db87f4747b8191a6d3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 06:48:30 -0700 Subject: [PATCH 18/28] [release/10.0.1xx] Source code updates from dotnet/arcade (#2824) Co-authored-by: dotnet-maestro[bot] --- src/arcade/Arcade.slnx | 1 + src/arcade/eng/Version.Details.xml | 2 +- src/arcade/eng/common/SetupNugetSources.ps1 | 71 +++--- src/arcade/eng/common/SetupNugetSources.sh | 175 ++++++++------ .../BoundaryConditionTests.cs | 186 +++++++++++++++ .../CredentialHandlingTests.cs | 215 ++++++++++++++++++ .../FeedEnablingTests.cs | 179 +++++++++++++++ .../InternalFeedAdditionTests.cs | 149 ++++++++++++ ...soft.DotNet.SetupNugetSources.Tests.csproj | 25 ++ .../NoChangeScenarioTests.cs | 86 +++++++ .../NuGetConfigAssertions.cs | 190 ++++++++++++++++ .../ScriptRunner.cs | 125 ++++++++++ .../SetupNugetSourcesFixture.cs | 65 ++++++ .../SignToolTests.cs | 4 +- src/source-manifest.json | 4 +- 15 files changed, 1368 insertions(+), 109 deletions(-) create mode 100644 src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/BoundaryConditionTests.cs create mode 100644 src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/CredentialHandlingTests.cs create mode 100644 src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/FeedEnablingTests.cs create mode 100644 src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/InternalFeedAdditionTests.cs create mode 100644 src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/Microsoft.DotNet.SetupNugetSources.Tests.csproj create mode 100644 src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/NoChangeScenarioTests.cs create mode 100644 src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/NuGetConfigAssertions.cs create mode 100644 src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/ScriptRunner.cs create mode 100644 src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/SetupNugetSourcesFixture.cs diff --git a/src/arcade/Arcade.slnx b/src/arcade/Arcade.slnx index a4c51eaafd6..337ee9c2279 100644 --- a/src/arcade/Arcade.slnx +++ b/src/arcade/Arcade.slnx @@ -29,6 +29,7 @@ + diff --git a/src/arcade/eng/Version.Details.xml b/src/arcade/eng/Version.Details.xml index 8e4ff3e2e9b..1a9d65f0b49 100644 --- a/src/arcade/eng/Version.Details.xml +++ b/src/arcade/eng/Version.Details.xml @@ -1,6 +1,6 @@ - + diff --git a/src/arcade/eng/common/SetupNugetSources.ps1 b/src/arcade/eng/common/SetupNugetSources.ps1 index 9445c314325..fc8d618014e 100644 --- a/src/arcade/eng/common/SetupNugetSources.ps1 +++ b/src/arcade/eng/common/SetupNugetSources.ps1 @@ -7,7 +7,7 @@ # See example call for this script below. # # - task: PowerShell@2 -# displayName: Setup Private Feeds Credentials +# displayName: Setup internal Feeds Credentials # condition: eq(variables['Agent.OS'], 'Windows_NT') # inputs: # filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.ps1 @@ -34,19 +34,28 @@ Set-StrictMode -Version 2.0 . $PSScriptRoot\tools.ps1 +# Adds or enables the package source with the given name +function AddOrEnablePackageSource($sources, $disabledPackageSources, $SourceName, $SourceEndPoint, $creds, $Username, $pwd) { + if ($disabledPackageSources -eq $null -or -not (EnableInternalPackageSource -DisabledPackageSources $disabledPackageSources -Creds $creds -PackageSourceName $SourceName)) { + AddPackageSource -Sources $sources -SourceName $SourceName -SourceEndPoint $SourceEndPoint -Creds $creds -Username $userName -pwd $Password + } +} + # Add source entry to PackageSources function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $pwd) { $packageSource = $sources.SelectSingleNode("add[@key='$SourceName']") if ($packageSource -eq $null) { + Write-Host "Adding package source $SourceName" + $packageSource = $doc.CreateElement("add") $packageSource.SetAttribute("key", $SourceName) $packageSource.SetAttribute("value", $SourceEndPoint) $sources.AppendChild($packageSource) | Out-Null } else { - Write-Host "Package source $SourceName already present." + Write-Host "Package source $SourceName already present and enabled." } AddCredential -Creds $creds -Source $SourceName -Username $Username -pwd $pwd @@ -59,6 +68,8 @@ function AddCredential($creds, $source, $username, $pwd) { return; } + Write-Host "Inserting credential for feed: " $source + # Looks for credential configuration for the given SourceName. Create it if none is found. $sourceElement = $creds.SelectSingleNode($Source) if ($sourceElement -eq $null) @@ -91,24 +102,27 @@ function AddCredential($creds, $source, $username, $pwd) { $passwordElement.SetAttribute("value", $pwd) } -function InsertMaestroPrivateFeedCredentials($Sources, $Creds, $Username, $pwd) { - $maestroPrivateSources = $Sources.SelectNodes("add[contains(@key,'darc-int')]") - - Write-Host "Inserting credentials for $($maestroPrivateSources.Count) Maestro's private feeds." - - ForEach ($PackageSource in $maestroPrivateSources) { - Write-Host "`tInserting credential for Maestro's feed:" $PackageSource.Key - AddCredential -Creds $creds -Source $PackageSource.Key -Username $Username -pwd $pwd +# Enable all darc-int package sources. +function EnableMaestroInternalPackageSources($DisabledPackageSources, $Creds) { + $maestroInternalSources = $DisabledPackageSources.SelectNodes("add[contains(@key,'darc-int')]") + ForEach ($DisabledPackageSource in $maestroInternalSources) { + EnableInternalPackageSource -DisabledPackageSources $DisabledPackageSources -Creds $Creds -PackageSourceName $DisabledPackageSource.key } } -function EnablePrivatePackageSources($DisabledPackageSources) { - $maestroPrivateSources = $DisabledPackageSources.SelectNodes("add[contains(@key,'darc-int')]") - ForEach ($DisabledPackageSource in $maestroPrivateSources) { - Write-Host "`tEnsuring private source '$($DisabledPackageSource.key)' is enabled by deleting it from disabledPackageSource" +# Enables an internal package source by name, if found. Returns true if the package source was found and enabled, false otherwise. +function EnableInternalPackageSource($DisabledPackageSources, $Creds, $PackageSourceName) { + $DisabledPackageSource = $DisabledPackageSources.SelectSingleNode("add[@key='$PackageSourceName']") + if ($DisabledPackageSource) { + Write-Host "Enabling internal source '$($DisabledPackageSource.key)'." + # Due to https://github.com/NuGet/Home/issues/10291, we must actually remove the disabled entries $DisabledPackageSources.RemoveChild($DisabledPackageSource) + + AddCredential -Creds $creds -Source $DisabledPackageSource.Key -Username $userName -pwd $Password + return $true } + return $false } if (!(Test-Path $ConfigFile -PathType Leaf)) { @@ -121,15 +135,17 @@ $doc = New-Object System.Xml.XmlDocument $filename = (Get-Item $ConfigFile).FullName $doc.Load($filename) -# Get reference to or create one if none exist already +# Get reference to - fail if none exist $sources = $doc.DocumentElement.SelectSingleNode("packageSources") if ($sources -eq $null) { - $sources = $doc.CreateElement("packageSources") - $doc.DocumentElement.AppendChild($sources) | Out-Null + Write-PipelineTelemetryError -Category 'Build' -Message "Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. NuGet config file must contain a packageSources section: $ConfigFile" + ExitWithExitCode 1 } $creds = $null +$feedSuffix = "v3/index.json" if ($Password) { + $feedSuffix = "v2" # Looks for a node. Create it if none is found. $creds = $doc.DocumentElement.SelectSingleNode("packageSourceCredentials") if ($creds -eq $null) { @@ -138,33 +154,22 @@ if ($Password) { } } +$userName = "dn-bot" + # Check for disabledPackageSources; we'll enable any darc-int ones we find there $disabledSources = $doc.DocumentElement.SelectSingleNode("disabledPackageSources") if ($disabledSources -ne $null) { Write-Host "Checking for any darc-int disabled package sources in the disabledPackageSources node" - EnablePrivatePackageSources -DisabledPackageSources $disabledSources -} - -$userName = "dn-bot" - -# Insert credential nodes for Maestro's private feeds -InsertMaestroPrivateFeedCredentials -Sources $sources -Creds $creds -Username $userName -pwd $Password - -# 3.1 uses a different feed url format so it's handled differently here -$dotnet31Source = $sources.SelectSingleNode("add[@key='dotnet3.1']") -if ($dotnet31Source -ne $null) { - AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v2" -Creds $creds -Username $userName -pwd $Password - AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2" -Creds $creds -Username $userName -pwd $Password + EnableMaestroInternalPackageSources -DisabledPackageSources $disabledSources -Creds $creds } - $dotnetVersions = @('5','6','7','8','9','10') foreach ($dotnetVersion in $dotnetVersions) { $feedPrefix = "dotnet" + $dotnetVersion; $dotnetSource = $sources.SelectSingleNode("add[@key='$feedPrefix']") if ($dotnetSource -ne $null) { - AddPackageSource -Sources $sources -SourceName "$feedPrefix-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal/nuget/v2" -Creds $creds -Username $userName -pwd $Password - AddPackageSource -Sources $sources -SourceName "$feedPrefix-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal-transport/nuget/v2" -Creds $creds -Username $userName -pwd $Password + AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "$feedPrefix-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password + AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "$feedPrefix-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal-transport/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password } } diff --git a/src/arcade/eng/common/SetupNugetSources.sh b/src/arcade/eng/common/SetupNugetSources.sh index ddf4efc81a4..dd2564aef01 100755 --- a/src/arcade/eng/common/SetupNugetSources.sh +++ b/src/arcade/eng/common/SetupNugetSources.sh @@ -52,78 +52,126 @@ if [[ `uname -s` == "Darwin" ]]; then TB='' fi -# Ensure there is a ... section. -grep -i "" $ConfigFile -if [ "$?" != "0" ]; then - echo "Adding ... section." - ConfigNodeHeader="" - PackageSourcesTemplate="${TB}${NL}${TB}" +# Enables an internal package source by name, if found. Returns 0 if found and enabled, 1 if not found. +EnableInternalPackageSource() { + local PackageSourceName="$1" + + # Check if disabledPackageSources section exists + grep -i "" "$ConfigFile" > /dev/null + if [ "$?" != "0" ]; then + return 1 # No disabled sources section + fi + + # Check if this source name is disabled + grep -i " /dev/null + if [ "$?" == "0" ]; then + echo "Enabling internal source '$PackageSourceName'." + # Remove the disabled entry + local OldDisableValue="" + local NewDisableValue="" + sed -i.bak "s|$OldDisableValue|$NewDisableValue|" "$ConfigFile" + + # Add the source name to PackageSources for credential handling + PackageSources+=("$PackageSourceName") + return 0 # Found and enabled + fi + + return 1 # Not found in disabled sources +} + +# Add source entry to PackageSources +AddPackageSource() { + local SourceName="$1" + local SourceEndPoint="$2" + + # Check if source already exists + grep -i " /dev/null + if [ "$?" == "0" ]; then + echo "Package source $SourceName already present and enabled." + PackageSources+=("$SourceName") + return + fi + + echo "Adding package source $SourceName" + PackageSourcesNodeFooter="" + PackageSourceTemplate="${TB}" + + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" "$ConfigFile" + PackageSources+=("$SourceName") +} + +# Adds or enables the package source with the given name +AddOrEnablePackageSource() { + local SourceName="$1" + local SourceEndPoint="$2" + + # Try to enable if disabled, if not found then add new source + EnableInternalPackageSource "$SourceName" + if [ "$?" != "0" ]; then + AddPackageSource "$SourceName" "$SourceEndPoint" + fi +} - sed -i.bak "s|$ConfigNodeHeader|$ConfigNodeHeader${NL}$PackageSourcesTemplate|" $ConfigFile -fi +# Enable all darc-int package sources +EnableMaestroInternalPackageSources() { + # Check if disabledPackageSources section exists + grep -i "" "$ConfigFile" > /dev/null + if [ "$?" != "0" ]; then + return # No disabled sources section + fi + + # Find all darc-int disabled sources + local DisabledDarcIntSources=() + DisabledDarcIntSources+=$(grep -oh '"darc-int-[^"]*" value="true"' "$ConfigFile" | tr -d '"') + + for DisabledSourceName in ${DisabledDarcIntSources[@]} ; do + if [[ $DisabledSourceName == darc-int* ]]; then + EnableInternalPackageSource "$DisabledSourceName" + fi + done +} -# Ensure there is a ... section. -grep -i "" $ConfigFile +# Ensure there is a ... section. +grep -i "" $ConfigFile if [ "$?" != "0" ]; then - echo "Adding ... section." - - PackageSourcesNodeFooter="" - PackageSourceCredentialsTemplate="${TB}${NL}${TB}" - - sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourcesNodeFooter${NL}$PackageSourceCredentialsTemplate|" $ConfigFile + Write-PipelineTelemetryError -Category 'Build' "Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. NuGet config file must contain a packageSources section: $ConfigFile" + ExitWithExitCode 1 fi PackageSources=() -# Ensure dotnet3.1-internal and dotnet3.1-internal-transport are in the packageSources if the public dotnet3.1 feeds are present -grep -i "... section. + grep -i "" $ConfigFile if [ "$?" != "0" ]; then - echo "Adding dotnet3.1-internal to the packageSources." - PackageSourcesNodeFooter="" - PackageSourceTemplate="${TB}" + echo "Adding ... section." - sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile - fi - PackageSources+=('dotnet3.1-internal') - - grep -i "" $ConfigFile - if [ "$?" != "0" ]; then - echo "Adding dotnet3.1-internal-transport to the packageSources." PackageSourcesNodeFooter="" - PackageSourceTemplate="${TB}" + PackageSourceCredentialsTemplate="${TB}${NL}${TB}" - sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourcesNodeFooter${NL}$PackageSourceCredentialsTemplate|" $ConfigFile fi - PackageSources+=('dotnet3.1-internal-transport') +fi + +# Check for disabledPackageSources; we'll enable any darc-int ones we find there +grep -i "" $ConfigFile > /dev/null +if [ "$?" == "0" ]; then + echo "Checking for any darc-int disabled package sources in the disabledPackageSources node" + EnableMaestroInternalPackageSources fi DotNetVersions=('5' '6' '7' '8' '9' '10') for DotNetVersion in ${DotNetVersions[@]} ; do FeedPrefix="dotnet${DotNetVersion}"; - grep -i " /dev/null if [ "$?" == "0" ]; then - grep -i "" - - sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile - fi - PackageSources+=("$FeedPrefix-internal") - - grep -i "" $ConfigFile - if [ "$?" != "0" ]; then - echo "Adding $FeedPrefix-internal-transport to the packageSources." - PackageSourcesNodeFooter="" - PackageSourceTemplate="${TB}" - - sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile - fi - PackageSources+=("$FeedPrefix-internal-transport") + AddOrEnablePackageSource "$FeedPrefix-internal" "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$FeedPrefix-internal/nuget/$FeedSuffix" + AddOrEnablePackageSource "$FeedPrefix-internal-transport" "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$FeedPrefix-internal-transport/nuget/$FeedSuffix" fi done @@ -139,29 +187,12 @@ if [ "$CredToken" ]; then # Check if there is no existing credential for this FeedName grep -i "<$FeedName>" $ConfigFile if [ "$?" != "0" ]; then - echo "Adding credentials for $FeedName." + echo " Inserting credential for feed: $FeedName" PackageSourceCredentialsNodeFooter="" - NewCredential="${TB}${TB}<$FeedName>${NL}${NL}${NL}" + NewCredential="${TB}${TB}<$FeedName>${NL}${TB}${NL}${TB}${TB}${NL}${TB}${TB}" sed -i.bak "s|$PackageSourceCredentialsNodeFooter|$NewCredential${NL}$PackageSourceCredentialsNodeFooter|" $ConfigFile fi done fi - -# Re-enable any entries in disabledPackageSources where the feed name contains darc-int -grep -i "" $ConfigFile -if [ "$?" == "0" ]; then - DisabledDarcIntSources=() - echo "Re-enabling any disabled \"darc-int\" package sources in $ConfigFile" - DisabledDarcIntSources+=$(grep -oh '"darc-int-[^"]*" value="true"' $ConfigFile | tr -d '"') - for DisabledSourceName in ${DisabledDarcIntSources[@]} ; do - if [[ $DisabledSourceName == darc-int* ]] - then - OldDisableValue="" - NewDisableValue="" - sed -i.bak "s|$OldDisableValue|$NewDisableValue|" $ConfigFile - echo "Neutralized disablePackageSources entry for '$DisabledSourceName'" - fi - done -fi diff --git a/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/BoundaryConditionTests.cs b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/BoundaryConditionTests.cs new file mode 100644 index 00000000000..96366159bed --- /dev/null +++ b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/BoundaryConditionTests.cs @@ -0,0 +1,186 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.DotNet.XUnitExtensions; +using Xunit; + +namespace Microsoft.DotNet.SetupNugetSources.Tests +{ + public class BoundaryConditionTests : IClassFixture, IDisposable + { + private readonly ScriptRunner _scriptRunner; + private readonly string _testOutputDirectory; + + public BoundaryConditionTests(SetupNugetSourcesFixture fixture) + { + _testOutputDirectory = Path.Combine(Path.GetTempPath(), "SetupNugetSourcesTests", Guid.NewGuid().ToString()); + Directory.CreateDirectory(_testOutputDirectory); + _scriptRunner = fixture.ScriptRunner; + } + + public void Dispose() + { + try + { + if (Directory.Exists(_testOutputDirectory)) + { + Directory.Delete(_testOutputDirectory, true); + } + } + catch { } + } + + [Fact] + public async Task EmptyConfiguration_FailsWithoutPackageSourcesSection() + { + // Arrange + var originalConfig = @" + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(1, "Script should fail when packageSources section is missing"); + + // Check both output and error for the message (scripts may write to stdout instead of stderr) + var errorMessage = string.IsNullOrEmpty(result.error) ? result.output : result.error; + errorMessage.Should().Contain("packageSources section", "should report missing packageSources section error"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Config should remain unchanged when script fails + modifiedConfig.Should().BeEquivalentTo(originalConfig, "config should not be modified when script fails"); + } + + [Fact] + public async Task ConfigWithoutPackageSourcesSection_FailsWithoutPackageSourcesSection() + { + // Arrange + var originalConfig = @" + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(1, "Script should fail when packageSources section is missing"); + // Check both output and error for the message (scripts may write to stdout instead of stderr) + var errorMessage = string.IsNullOrEmpty(result.error) ? result.output : result.error; + errorMessage.Should().Contain("packageSources section", "should report missing packageSources section error"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Config should remain unchanged when script fails + modifiedConfig.Should().BeEquivalentTo(originalConfig, "config should not be modified when script fails"); + } + + [Fact] + public async Task ConfigWithMissingDisabledPackageSourcesSection_StillAddsInternalFeeds() + { + // Arrange + var originalConfig = @" + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "Script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Should still add internal feeds + modifiedConfig.ShouldContainPackageSource("dotnet6-internal"); + modifiedConfig.ShouldContainPackageSource("dotnet6-internal-transport"); + } + + [Fact] + public async Task NonExistentConfigFile_ReturnsError() + { + // Arrange + var nonExistentPath = Path.Combine(_testOutputDirectory, "nonexistent.config"); + // Act + var result = await _scriptRunner.RunScript(nonExistentPath); + + // Assert + result.exitCode.Should().Be(1, "should return error code for nonexistent file"); + // Check both output and error for the message (scripts may write to stdout instead of stderr) + var errorMessage = string.IsNullOrEmpty(result.error) ? result.output : result.error; + errorMessage.Should().Contain("Couldn't find the NuGet config file", "should report missing file error"); + } + + [Fact] + public async Task ConfigWithOnlyDisabledSources_FailsWithoutPackageSourcesSection() + { + // Arrange + var originalConfig = @" + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(1, "Script should fail when packageSources section is missing"); + // Check both output and error for the message (scripts may write to stdout instead of stderr) + var errorMessage = string.IsNullOrEmpty(result.error) ? result.output : result.error; + errorMessage.Should().Contain("packageSources section", "should report missing packageSources section error"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Config should remain unchanged when script fails + modifiedConfig.Should().BeEquivalentTo(originalConfig, "config should not be modified when script fails"); + } + + [Fact] + public async Task ConfigWithEmptyPackageSourcesSection_HandlesCorrectly() + { + // Arrange + var originalConfig = @" + + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "Script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Should enable darc-int feeds but not add any dotnet internal feeds since no dotnet feeds exist + modifiedConfig.ShouldNotBeDisabled("darc-int-dotnet-roslyn-12345", "should enable darc-int feed"); + modifiedConfig.GetPackageSourceCount().Should().Be(0, "should not add dotnet internal feeds without dotnet public feeds"); + } + } +} + + diff --git a/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/CredentialHandlingTests.cs b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/CredentialHandlingTests.cs new file mode 100644 index 00000000000..a9cf811728b --- /dev/null +++ b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/CredentialHandlingTests.cs @@ -0,0 +1,215 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.DotNet.XUnitExtensions; +using Xunit; + +namespace Microsoft.DotNet.SetupNugetSources.Tests +{ + public class CredentialHandlingTests : IClassFixture, IDisposable + { + private readonly ScriptRunner _scriptRunner; + private readonly string _testOutputDirectory; + + public CredentialHandlingTests(SetupNugetSourcesFixture fixture) + { + _testOutputDirectory = Path.Combine(Path.GetTempPath(), "SetupNugetSourcesTests", Guid.NewGuid().ToString()); + Directory.CreateDirectory(_testOutputDirectory); + _scriptRunner = fixture.ScriptRunner; + } + + public void Dispose() + { + try + { + if (Directory.Exists(_testOutputDirectory)) + { + Directory.Delete(_testOutputDirectory, true); + } + } + catch { } + } + + [Fact] + public async Task ConfigWithCredentialProvided_AddsCredentialsForInternalFeeds() + { + // Arrange + var originalConfig = @" + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + var testCredential = "Placeholder"; + // Act + var result = await _scriptRunner.RunScript(configPath, testCredential); + + // Assert + result.exitCode.Should().Be(0, "script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Should add internal feeds + modifiedConfig.ShouldContainPackageSource("dotnet6-internal"); + modifiedConfig.ShouldContainPackageSource("dotnet6-internal-transport"); + + // Should add credentials for internal feeds + modifiedConfig.ShouldContainCredentials("dotnet6-internal", "dn-bot", "should add credentials for internal feed"); + modifiedConfig.ShouldContainCredentials("dotnet6-internal-transport", "dn-bot", "should add credentials for transport feed"); + + // Should use v2 endpoints when credentials are provided + modifiedConfig.ShouldContainPackageSource("dotnet6-internal", + "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal/nuget/v2", + "should use v2 endpoint when credentials provided"); + modifiedConfig.ShouldContainPackageSource("dotnet6-internal-transport", + "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal-transport/nuget/v2", + "should use v2 endpoint when credentials provided"); + } + + [Fact] + public async Task ConfigWithNoCredential_DoesNotAddCredentials() + { + // Arrange + var originalConfig = @" + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + + // Act - No credential provided + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Should add internal feeds + modifiedConfig.ShouldContainPackageSource("dotnet6-internal"); + modifiedConfig.ShouldContainPackageSource("dotnet6-internal-transport"); + + // Should NOT add credentials + modifiedConfig.ShouldNotContainCredentials("dotnet6-internal", "should not add credentials without credential"); + modifiedConfig.ShouldNotContainCredentials("dotnet6-internal-transport", "should not add credentials without credential"); + + // Should use v3 endpoints when no credentials are provided + modifiedConfig.ShouldContainPackageSource("dotnet6-internal", + "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal/nuget/v3/index.json", + "should use v3 endpoint when no credentials provided"); + } + + [Fact] + public async Task ConfigWithExistingCredentials_PreservesAndAddsNew() + { + // Arrange + var originalConfig = @" + + + + + + + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + var testCredential = "Placeholder"; + // Act + var result = await _scriptRunner.RunScript(configPath, testCredential); + + // Assert + result.exitCode.Should().Be(0, "script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Should preserve existing credentials + modifiedConfig.ShouldContainCredentials("existing-private", "existing-user", "should preserve existing credentials"); + + // Should add new credentials for internal feeds + modifiedConfig.ShouldContainCredentials("dotnet6-internal", "dn-bot", "should add credentials for new internal feed"); + modifiedConfig.ShouldContainCredentials("dotnet6-internal-transport", "dn-bot", "should add credentials for new transport feed"); + } + + [Fact] + public async Task ConfigWithDarcIntFeeds_AddsCredentialsForEnabledFeeds() + { + // Arrange + var originalConfig = @" + + + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + var testCredential = "Placeholder"; + // Act + var result = await _scriptRunner.RunScript(configPath, testCredential); + + // Assert + result.exitCode.Should().Be(0, "script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Should enable the darc-int feed + modifiedConfig.ShouldNotBeDisabled("darc-int-dotnet-roslyn-12345", "darc-int feed should be enabled"); + + // Should add credentials for enabled darc-int feed + modifiedConfig.ShouldContainCredentials("darc-int-dotnet-roslyn-12345", "dn-bot", "should add credentials for enabled darc-int feed"); + + // Should add credentials for new internal feeds + modifiedConfig.ShouldContainCredentials("dotnet6-internal", "dn-bot", "should add credentials for internal feed"); + modifiedConfig.ShouldContainCredentials("dotnet6-internal-transport", "dn-bot", "should add credentials for transport feed"); + } + + [Fact] + public async Task ConfigWithNoCredentialButExistingCredentials_DoesNotRemoveExistingCredentials() + { + // Arrange + var originalConfig = @" + + + + + + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + + // Act - No credential provided + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Should preserve existing credentials + modifiedConfig.ShouldContainCredentials("dotnet6-internal", "dn-bot", "should preserve existing credentials"); + + // Should not add credentials for new feeds without credential + modifiedConfig.ShouldNotContainCredentials("dotnet6-internal-transport", "should not add credentials without credential"); + } + } +} diff --git a/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/FeedEnablingTests.cs b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/FeedEnablingTests.cs new file mode 100644 index 00000000000..7af694a1db8 --- /dev/null +++ b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/FeedEnablingTests.cs @@ -0,0 +1,179 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Threading.Tasks; +using FluentAssertions; +using Xunit; + +namespace Microsoft.DotNet.SetupNugetSources.Tests +{ + public class FeedEnablingTests : IClassFixture, IDisposable + { + private readonly ScriptRunner _scriptRunner; + private readonly string _testOutputDirectory; + + public FeedEnablingTests(SetupNugetSourcesFixture fixture) + { + _testOutputDirectory = Path.Combine(Path.GetTempPath(), "SetupNugetSourcesTests", Guid.NewGuid().ToString()); + Directory.CreateDirectory(_testOutputDirectory); + _scriptRunner = fixture.ScriptRunner; + } + + public void Dispose() + { + try + { + if (Directory.Exists(_testOutputDirectory)) + { + Directory.Delete(_testOutputDirectory, true); + } + } + catch { } + } + + [Fact] + public async Task ConfigWithDisabledDarcIntFeeds_EnablesFeeds() + { + // Arrange + var originalConfig = @" + + + + + + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "Script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Darc-int feeds should no longer be disabled + modifiedConfig.ShouldNotBeDisabled("darc-int-dotnet-roslyn-12345", "darc-int feed should be enabled"); + modifiedConfig.ShouldNotBeDisabled("darc-int-dotnet-runtime-67890", "darc-int feed should be enabled"); + + // Should also add internal feeds for dotnet6 + modifiedConfig.ShouldContainPackageSource("dotnet6-internal", + "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal/nuget/v3/index.json", + "should add dotnet6-internal feed"); + modifiedConfig.ShouldContainPackageSource("dotnet6-internal-transport", + "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal-transport/nuget/v3/index.json", + "should add dotnet6-internal-transport feed"); + } + + [Fact] + public async Task ConfigWithMixedDisabledFeeds_OnlyEnablesDarcIntFeeds() + { + // Arrange + var originalConfig = @" + + + + + + + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "Script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Darc-int feeds should be enabled + modifiedConfig.ShouldNotBeDisabled("darc-int-dotnet-roslyn-12345", "darc-int feed should be enabled"); + modifiedConfig.ShouldNotBeDisabled("darc-int-dotnet-runtime-67890", "darc-int feed should be enabled"); + + // Non-darc-int feeds should remain disabled + modifiedConfig.ShouldBeDisabled("some-other-feed", "non-darc-int feed should remain disabled"); + modifiedConfig.ShouldBeDisabled("another-disabled-feed", "non-darc-int feed should remain disabled"); + } + + [Fact] + public async Task ConfigWithDisabledInternalFeed_EnablesExistingInsteadOfAdding() + { + // Arrange + var originalConfig = @" + + + + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "Script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // The dotnet6-internal feed should be enabled (removed from disabled sources) + modifiedConfig.ShouldNotBeDisabled("dotnet6-internal", "internal feed should be enabled"); + + // Should still add the transport feed + modifiedConfig.ShouldContainPackageSource("dotnet6-internal-transport", + "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal-transport/nuget/v3/index.json", + "should add transport feed"); + + // Should have 4 package sources (original 3, with dotnet6-internal enabled + transport added) + modifiedConfig.GetPackageSourceCount().Should().Be(4, "should enable existing feed and add transport feed"); + } + + [Fact] + public async Task ConfigWithNoDisabledSources_StillAddsInternalFeeds() + { + // Arrange + var originalConfig = @" + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "Script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Should add internal feeds even without disabled sources section + modifiedConfig.ShouldContainPackageSource("dotnet6-internal", + "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal/nuget/v3/index.json", + "should add dotnet6-internal feed"); + modifiedConfig.ShouldContainPackageSource("dotnet6-internal-transport", + "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal-transport/nuget/v3/index.json", + "should add dotnet6-internal-transport feed"); + } + } +} diff --git a/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/InternalFeedAdditionTests.cs b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/InternalFeedAdditionTests.cs new file mode 100644 index 00000000000..ca42421c401 --- /dev/null +++ b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/InternalFeedAdditionTests.cs @@ -0,0 +1,149 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.DotNet.XUnitExtensions; +using Xunit; + +namespace Microsoft.DotNet.SetupNugetSources.Tests +{ + public class InternalFeedAdditionTests : IClassFixture, IDisposable + { + private readonly ScriptRunner _scriptRunner; + private readonly string _testOutputDirectory; + + public InternalFeedAdditionTests(SetupNugetSourcesFixture fixture) + { + _testOutputDirectory = Path.Combine(Path.GetTempPath(), "SetupNugetSourcesTests", Guid.NewGuid().ToString()); + Directory.CreateDirectory(_testOutputDirectory); + _scriptRunner = fixture.ScriptRunner; + } + + public void Dispose() + { + try + { + if (Directory.Exists(_testOutputDirectory)) + { + Directory.Delete(_testOutputDirectory, true); + } + } + catch { } + } + + [Theory] + [InlineData("dotnet5")] + [InlineData("dotnet6")] + [InlineData("dotnet7")] + [InlineData("dotnet8")] + [InlineData("dotnet9")] + [InlineData("dotnet10")] + public async Task ConfigWithSpecificDotNetVersion_AddsCorrespondingInternalFeeds(string dotnetVersion) + { + // Arrange + var originalConfig = $@" + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "Script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + modifiedConfig.ShouldContainPackageSource($"{dotnetVersion}-internal", + $"https://pkgs.dev.azure.com/dnceng/internal/_packaging/{dotnetVersion}-internal/nuget/v3/index.json", + $"should add {dotnetVersion}-internal feed"); + modifiedConfig.ShouldContainPackageSource($"{dotnetVersion}-internal-transport", + $"https://pkgs.dev.azure.com/dnceng/internal/_packaging/{dotnetVersion}-internal-transport/nuget/v3/index.json", + $"should add {dotnetVersion}-internal-transport feed"); + } + + [Fact] + public async Task ConfigWithMultipleDotNetVersions_AddsAllInternalFeeds() + { + // Arrange + var originalConfig = @" + + + + + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "Script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Should add internal feeds for all versions + var versions = new[] { "dotnet5", "dotnet6", "dotnet7", "dotnet8", "dotnet9", "dotnet10" }; + foreach (var version in versions) + { + modifiedConfig.ShouldContainPackageSource($"{version}-internal", + $"https://pkgs.dev.azure.com/dnceng/internal/_packaging/{version}-internal/nuget/v3/index.json", + $"should add {version}-internal feed"); + modifiedConfig.ShouldContainPackageSource($"{version}-internal-transport", + $"https://pkgs.dev.azure.com/dnceng/internal/_packaging/{version}-internal-transport/nuget/v3/index.json", + $"should add {version}-internal-transport feed"); + } + + // Original count (7 sources) + 12 internal sources = 19 total + modifiedConfig.GetPackageSourceCount().Should().Be(19, "should have all original sources plus internal feeds"); + } + + [Fact] + public async Task ConfigWithExistingInternalFeed_DoesNotDuplicate() + { + // Arrange + var originalConfig = @" + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "Script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + + // Should still contain the dotnet6-internal feed (only once) + modifiedConfig.ShouldContainPackageSource("dotnet6-internal", + "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal/nuget/v3/index.json", + "existing internal feed should be preserved"); + + // Should add the missing transport feed + modifiedConfig.ShouldContainPackageSource("dotnet6-internal-transport", + "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal-transport/nuget/v3/index.json", + "should add missing transport feed"); + + // Should have 4 total sources (3 original + 1 added transport) + modifiedConfig.GetPackageSourceCount().Should().Be(4, "should not duplicate existing sources"); + } + } +} + + diff --git a/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/Microsoft.DotNet.SetupNugetSources.Tests.csproj b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/Microsoft.DotNet.SetupNugetSources.Tests.csproj new file mode 100644 index 00000000000..83d868c3bdc --- /dev/null +++ b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/Microsoft.DotNet.SetupNugetSources.Tests.csproj @@ -0,0 +1,25 @@ + + + + $(NetToolCurrent) + true + + + + + + + + + + + + + + + + + + + + diff --git a/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/NoChangeScenarioTests.cs b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/NoChangeScenarioTests.cs new file mode 100644 index 00000000000..632511d3441 --- /dev/null +++ b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/NoChangeScenarioTests.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.DotNet.XUnitExtensions; +using Xunit; + +namespace Microsoft.DotNet.SetupNugetSources.Tests +{ + public class NoChangeScenarioTests : IClassFixture, IDisposable + { + private readonly ScriptRunner _scriptRunner; + private readonly string _testOutputDirectory; + + public NoChangeScenarioTests(SetupNugetSourcesFixture fixture) + { + _testOutputDirectory = Path.Combine(Path.GetTempPath(), "SetupNugetSourcesTests", Guid.NewGuid().ToString()); + Directory.CreateDirectory(_testOutputDirectory); + _scriptRunner = fixture.ScriptRunner; + } + + public void Dispose() + { + try + { + if (Directory.Exists(_testOutputDirectory)) + { + Directory.Delete(_testOutputDirectory, true); + } + } + catch { } + } + + + + [Fact] + public async Task BasicConfig_NoChanges() + { + // Arrange + var originalConfig = @" + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + modifiedConfig.ShouldBeSemanticallySame(originalConfig, "basic config with no special feeds should not be modified"); + } + + [Fact] + public async Task ConfigWithNonDotNetFeeds_NoChanges() + { + // Arrange + var originalConfig = @" + + + + + + +"; + var configPath = Path.Combine(_testOutputDirectory, "nuget.config"); + await Task.Run(() => File.WriteAllText(configPath, originalConfig)); + // Act + var result = await _scriptRunner.RunScript(configPath); + + // Assert + result.exitCode.Should().Be(0, "Script should succeed, but got error: {result.error}"); + var modifiedConfig = await Task.Run(() => File.ReadAllText(configPath)); + modifiedConfig.ShouldBeSemanticallySame(originalConfig, "config with non-dotnet feeds should not be modified"); + } + } +} + + diff --git a/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/NuGetConfigAssertions.cs b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/NuGetConfigAssertions.cs new file mode 100644 index 00000000000..0bd0f5b5dfd --- /dev/null +++ b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/NuGetConfigAssertions.cs @@ -0,0 +1,190 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Linq; +using FluentAssertions; + +namespace Microsoft.DotNet.SetupNugetSources.Tests +{ + public static class NuGetConfigAssertions + { + /// + /// Compares two NuGet.config files for semantic equality, ignoring whitespace differences + /// + public static void ShouldBeSemanticallySame(this string actualContent, string expectedContent, string because = "") + { + var actualNormalized = NormalizeXml(actualContent); + var expectedNormalized = NormalizeXml(expectedContent); + + actualNormalized.Should().Be(expectedNormalized, because); + } + + /// + /// Asserts that the config contains a package source with the specified key + /// + public static void ShouldContainPackageSource(this string configContent, string key, string value = null, string because = "") + { + var doc = XDocument.Parse(configContent); + var packageSources = doc.Root?.Element("packageSources"); + packageSources.Should().NotBeNull($"packageSources section should exist {because}"); + + var source = packageSources.Elements("add").FirstOrDefault(e => e.Attribute("key")?.Value == key); + source.Should().NotBeNull($"package source '{key}' should exist {because}"); + + if (value != null) + { + source.Attribute("value")?.Value.Should().Be(value, $"package source '{key}' should have the correct value {because}"); + } + } + + /// + /// Asserts that the config does not contain a package source with the specified key + /// + public static void ShouldNotContainPackageSource(this string configContent, string key, string because = "") + { + var doc = XDocument.Parse(configContent); + var packageSources = doc.Root?.Element("packageSources"); + + if (packageSources != null) + { + var source = packageSources.Elements("add").FirstOrDefault(e => e.Attribute("key")?.Value == key); + source.Should().BeNull($"package source '{key}' should not exist {because}"); + } + } + + /// + /// Asserts that the config contains credentials for the specified source + /// + public static void ShouldContainCredentials(this string configContent, string sourceName, string username = null, string because = "") + { + var doc = XDocument.Parse(configContent); + var credentials = doc.Root?.Element("packageSourceCredentials"); + credentials.Should().NotBeNull($"packageSourceCredentials section should exist {because}"); + + var sourceCredentials = credentials.Element(sourceName); + sourceCredentials.Should().NotBeNull($"credentials for '{sourceName}' should exist {because}"); + + if (username != null) + { + var usernameElement = sourceCredentials.Elements("add").FirstOrDefault(e => e.Attribute("key")?.Value == "Username"); + usernameElement.Should().NotBeNull($"username credential should exist for '{sourceName}' {because}"); + usernameElement.Attribute("value")?.Value.Should().Be(username, $"username should match for '{sourceName}' {because}"); + } + + var passwordElement = sourceCredentials.Elements("add").FirstOrDefault(e => e.Attribute("key")?.Value == "ClearTextPassword"); + passwordElement.Should().NotBeNull($"password credential should exist for '{sourceName}' {because}"); + } + + /// + /// Asserts that the config does not contain credentials for the specified source + /// + public static void ShouldNotContainCredentials(this string configContent, string sourceName, string because = "") + { + var doc = XDocument.Parse(configContent); + var credentials = doc.Root?.Element("packageSourceCredentials"); + + if (credentials != null) + { + var sourceCredentials = credentials.Element(sourceName); + sourceCredentials.Should().BeNull($"credentials for '{sourceName}' should not exist {because}"); + } + } + + /// + /// Asserts that a source is not in the disabled sources list + /// + public static void ShouldNotBeDisabled(this string configContent, string sourceName, string because = "") + { + var doc = XDocument.Parse(configContent); + var disabledSources = doc.Root?.Element("disabledPackageSources"); + + if (disabledSources != null) + { + var disabledSource = disabledSources.Elements("add").FirstOrDefault(e => e.Attribute("key")?.Value == sourceName); + disabledSource.Should().BeNull($"source '{sourceName}' should not be disabled {because}"); + } + } + + /// + /// Asserts that a source is in the disabled sources list + /// + public static void ShouldBeDisabled(this string configContent, string sourceName, string because = "") + { + var doc = XDocument.Parse(configContent); + var disabledSources = doc.Root?.Element("disabledPackageSources"); + disabledSources.Should().NotBeNull($"disabledPackageSources section should exist {because}"); + + var disabledSource = disabledSources.Elements("add").FirstOrDefault(e => e.Attribute("key")?.Value == sourceName); + disabledSource.Should().NotBeNull($"source '{sourceName}' should be disabled {because}"); + } + + /// + /// Counts the number of package sources in the config + /// + public static int GetPackageSourceCount(this string configContent) + { + var doc = XDocument.Parse(configContent); + var packageSources = doc.Root?.Element("packageSources"); + return packageSources?.Elements("add").Count() ?? 0; + } + + /// + /// Normalizes XML content for comparison by removing whitespace differences and sorting elements consistently + /// + private static string NormalizeXml(string xmlContent) + { + var doc = XDocument.Parse(xmlContent); + + // Sort package sources by key for consistent comparison + var packageSources = doc.Root?.Element("packageSources"); + if (packageSources != null) + { + var sortedSources = packageSources.Elements("add") + .OrderBy(e => e.Attribute("key")?.Value) + .ToList(); + packageSources.RemoveAll(); + foreach (var source in sortedSources) + { + packageSources.Add(source); + } + } + + // Sort disabled sources by key + var disabledSources = doc.Root?.Element("disabledPackageSources"); + if (disabledSources != null) + { + var sortedDisabled = disabledSources.Elements("add") + .OrderBy(e => e.Attribute("key")?.Value) + .ToList(); + disabledSources.RemoveAll(); + foreach (var source in sortedDisabled) + { + disabledSources.Add(source); + } + } + + // Sort credentials by source name + var credentials = doc.Root?.Element("packageSourceCredentials"); + if (credentials != null) + { + var sortedCredentials = credentials.Elements() + .OrderBy(e => e.Name.LocalName) + .ToList(); + credentials.RemoveAll(); + foreach (var cred in sortedCredentials) + { + credentials.Add(cred); + } + } + + return doc.ToString(SaveOptions.DisableFormatting); + } + } +} + + diff --git a/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/ScriptRunner.cs b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/ScriptRunner.cs new file mode 100644 index 00000000000..37dd8cb9d37 --- /dev/null +++ b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/ScriptRunner.cs @@ -0,0 +1,125 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.DotNet.SetupNugetSources.Tests +{ + public enum ScriptType + { + PowerShell, + Shell + } + + public class ScriptRunner + { + private readonly string _repoRoot; + + public ScriptRunner(string repoRoot) + { + _repoRoot = repoRoot ?? throw new ArgumentNullException(nameof(repoRoot)); + } + + public async Task<(int exitCode, string output, string error)> RunPowerShellScript(string configFilePath, string password = null) + { + var scriptPath = Path.Combine(_repoRoot, "eng", "common", "SetupNugetSources.ps1"); + var arguments = $"-ExecutionPolicy Bypass -File \"{scriptPath}\" -ConfigFile \"{configFilePath}\""; + + if (!string.IsNullOrEmpty(password)) + { + arguments += $" -Password \"{password}\""; + } + + return await RunProcess("powershell.exe", arguments, _repoRoot); + } + + public async Task<(int exitCode, string output, string error)> RunShellScript(string configFilePath, string credToken = null) + { + var scriptPath = Path.Combine(_repoRoot, "eng", "common", "SetupNugetSources.sh"); + + // Make script executable if on Unix + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + await RunProcess("chmod", $"+x \"{scriptPath}\"", _repoRoot); + } + + var arguments = $"\"{scriptPath}\" \"{configFilePath}\""; + if (!string.IsNullOrEmpty(credToken)) + { + arguments += $" \"{credToken}\""; + } + + var shell = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "bash.exe" : "/bin/bash"; + return await RunProcess(shell, arguments, _repoRoot); + } + + private async Task<(int exitCode, string output, string error)> RunProcess(string fileName, string arguments, string workingDirectory = null) + { + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = fileName, + Arguments = arguments, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + WorkingDirectory = workingDirectory ?? Directory.GetCurrentDirectory() + } + }; + + var outputBuilder = new StringBuilder(); + var errorBuilder = new StringBuilder(); + + process.OutputDataReceived += (sender, e) => + { + if (e.Data != null) + { + outputBuilder.AppendLine(e.Data); + } + }; + + process.ErrorDataReceived += (sender, e) => + { + if (e.Data != null) + { + errorBuilder.AppendLine(e.Data); + } + }; + + process.Start(); + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + await Task.Run(() => process.WaitForExit()); + + return (process.ExitCode, outputBuilder.ToString(), errorBuilder.ToString()); + } + + public async Task<(int exitCode, string output, string error)> RunScript(string configFilePath, string credential = null) + { + var scriptType = GetPlatformAppropriateScriptType(); + switch (scriptType) + { + case ScriptType.PowerShell: + return await RunPowerShellScript(configFilePath, credential); + case ScriptType.Shell: + return await RunShellScript(configFilePath, credential); + default: + throw new ArgumentException($"Unsupported script type: {scriptType}"); + } + } + + public static ScriptType GetPlatformAppropriateScriptType() + { + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ScriptType.PowerShell : ScriptType.Shell; + } + } +} + diff --git a/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/SetupNugetSourcesFixture.cs b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/SetupNugetSourcesFixture.cs new file mode 100644 index 00000000000..7e25ccd1b88 --- /dev/null +++ b/src/arcade/src/Microsoft.DotNet.SetupNugetSources.Tests/SetupNugetSourcesFixture.cs @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; + +namespace Microsoft.DotNet.SetupNugetSources.Tests +{ + /// + /// xUnit fixture that prepares a temporary repository root containing the + /// scaffolded files (global.json + eng/common scripts) copied from the + /// build output's RepoScaffold directory. Shared per test class. + /// + public class SetupNugetSourcesFixture : IDisposable + { + public string RepoRoot { get; } + public ScriptRunner ScriptRunner { get; } + + public SetupNugetSourcesFixture() + { + var scaffoldRoot = Path.Combine(AppContext.BaseDirectory, "RepoScaffold"); + if (!Directory.Exists(scaffoldRoot)) + { + throw new InvalidOperationException($"Expected scaffold directory not found: {scaffoldRoot}"); + } + + RepoRoot = Path.Combine(Path.GetTempPath(), "SetupNugetSourcesTestRepo", Guid.NewGuid().ToString()); + CopyDirectory(scaffoldRoot, RepoRoot); + + ScriptRunner = new ScriptRunner(RepoRoot); + } + + private static void CopyDirectory(string sourceDir, string destinationDir) + { + foreach (var dir in Directory.GetDirectories(sourceDir, "*", SearchOption.AllDirectories)) + { + var relative = Path.GetRelativePath(sourceDir, dir); + Directory.CreateDirectory(Path.Combine(destinationDir, relative)); + } + + foreach (var file in Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories)) + { + var relative = Path.GetRelativePath(sourceDir, file); + var destPath = Path.Combine(destinationDir, relative); + Directory.CreateDirectory(Path.GetDirectoryName(destPath)!); + File.Copy(file, destPath, overwrite: true); + } + } + + public void Dispose() + { + try + { + if (Directory.Exists(RepoRoot)) + { + Directory.Delete(RepoRoot, recursive: true); + } + } + catch + { + // Best effort cleanup. + } + } + } +} diff --git a/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs index 3b4cd8581ea..03672d1c263 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs @@ -480,7 +480,9 @@ private void ValidateProducedRpmContent( string layout = Path.Combine(tempDir, "layout"); Directory.CreateDirectory(layout); - ZipData.ExtractRpmPayloadContents(log: null, rpmPackage, layout); + var fakeBuildEngine = new FakeBuildEngine(_output); + var fakeLog = new TaskLoggingHelper(fakeBuildEngine, "TestLog"); + ZipData.ExtractRpmPayloadContents(fakeLog, rpmPackage, layout); // Checks: // Expected files are present diff --git a/src/source-manifest.json b/src/source-manifest.json index df15f47008c..2196f91ffcc 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -1,10 +1,10 @@ { "repositories": [ { - "barId": 286215, + "barId": 286474, "path": "arcade", "remoteUri": "https://github.com/dotnet/arcade", - "commitSha": "7ff6478d902606d65aa33cb8cedc2730e1843fe1" + "commitSha": "ba45f22d375e21c42fdc89695451932731d94552" }, { "barId": 286219, From 51064bb3f8289d596c559da52679f00c0b211551 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 14:37:58 +0000 Subject: [PATCH 19/28] [release/10.0.1xx] Source code updates from dotnet/sdk (#2825) Co-authored-by: dotnet-maestro[bot] --- src/sdk/NuGet.config | 2 + src/sdk/eng/Version.Details.props | 264 ++++----- src/sdk/eng/Version.Details.xml | 530 +++++++++--------- src/sdk/eng/Versions.props | 4 +- .../job/publish-build-assets.yml | 9 +- .../eng/common/core-templates/jobs/jobs.yml | 2 + .../common/post-build/nuget-verification.ps1 | 2 +- src/sdk/global.json | 4 +- .../DotNetDeltaApplier/PipeListener.cs | 83 ++- .../DotNetDeltaApplier/StartupHook.cs | 49 +- .../NamedPipeContract.cs | 50 +- .../WebAssemblyHotReload.cs | 3 +- .../HotReloadAgent/HotReloadAgent.cs | 69 ++- .../MetadataUpdateHandlerInvoker.cs | 2 +- .../HotReloadClient/DefaultHotReloadClient.cs | 67 ++- .../HotReloadClient/HotReloadClient.cs | 8 + .../HotReloadClient/HotReloadClients.cs | 35 +- .../Aspire/AspireServiceFactory.cs | 2 +- .../HotReload/CompilationHandler.cs | 47 +- .../HotReload/HotReloadDotNetWatcher.cs | 7 +- .../dotnet-watch/Process/RunningProject.cs | 29 +- .../BuiltInTools/dotnet-watch/UI/IReporter.cs | 1 + .../xlf/LocalizableStrings.cs.xlf | 2 +- .../xlf/LocalizableStrings.de.xlf | 2 +- .../xlf/LocalizableStrings.es.xlf | 2 +- .../xlf/LocalizableStrings.fr.xlf | 2 +- .../xlf/LocalizableStrings.it.xlf | 2 +- .../xlf/LocalizableStrings.ja.xlf | 2 +- .../xlf/LocalizableStrings.ko.xlf | 2 +- .../xlf/LocalizableStrings.pl.xlf | 2 +- .../xlf/LocalizableStrings.pt-BR.xlf | 2 +- .../xlf/LocalizableStrings.ru.xlf | 2 +- .../xlf/LocalizableStrings.tr.xlf | 2 +- .../xlf/LocalizableStrings.zh-Hans.xlf | 2 +- .../xlf/LocalizableStrings.zh-Hant.xlf | 2 +- .../dotnet/Commands/MSBuild/MSBuildLogger.cs | 17 +- .../src/Cli/dotnet/Commands/Run/RunCommand.cs | 2 + .../Cli/dotnet/Commands/Run/RunProperties.cs | 16 +- .../Run/VirtualProjectBuildingCommand.cs | 22 +- .../Commands/xlf/CliCommandStrings.cs.xlf | 18 +- .../Commands/xlf/CliCommandStrings.de.xlf | 18 +- .../Commands/xlf/CliCommandStrings.es.xlf | 18 +- .../Commands/xlf/CliCommandStrings.fr.xlf | 18 +- .../Commands/xlf/CliCommandStrings.it.xlf | 18 +- .../Commands/xlf/CliCommandStrings.ja.xlf | 18 +- .../Commands/xlf/CliCommandStrings.ko.xlf | 18 +- .../Commands/xlf/CliCommandStrings.pl.xlf | 18 +- .../Commands/xlf/CliCommandStrings.pt-BR.xlf | 18 +- .../Commands/xlf/CliCommandStrings.ru.xlf | 18 +- .../Commands/xlf/CliCommandStrings.tr.xlf | 18 +- .../xlf/CliCommandStrings.zh-Hans.xlf | 18 +- .../xlf/CliCommandStrings.zh-Hant.xlf | 18 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.cs.xlf | 2 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.de.xlf | 2 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.es.xlf | 2 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.fr.xlf | 2 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.it.xlf | 2 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.ja.xlf | 2 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.ko.xlf | 2 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.pl.xlf | 2 +- .../src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf | 2 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.ru.xlf | 2 +- src/sdk/src/Cli/dotnet/xlf/CliStrings.tr.xlf | 2 +- .../src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf | 2 +- .../src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf | 2 +- .../Layout/pkg/windows/bundles/sdk/bundle.wxs | 8 +- src/sdk/src/Layout/redist/dnx.ps1 | 8 - .../targets/GenerateInstallerLayout.targets | 1 - .../targets/GeneratePackagePruneData.targets | 9 +- .../redist/targets/OverlaySdkOnLKG.targets | 2 +- .../Tasks/sdk-tasks/sdk-tasks.InTree.targets | 1 - .../content/EditorConfig/Dotnet/.editorconfig | 2 +- .../MSTest-CSharp/Company.TestProject1.csproj | 4 +- .../MSTest-FSharp/Company.TestProject1.fsproj | 4 +- .../Company.TestProject1.vbproj | 4 +- .../Company.TestProject1.csproj | 6 +- .../TestProject/TestProject.csproj | 5 +- .../EditorConfig-file/.editorconfig | 2 +- .../HotReload/ApplyDeltaTests.cs | 58 ++ .../HotReload/RuntimeProcessLauncherTests.cs | 2 +- .../TestUtilities/AssertEx.cs | 3 +- .../MSBuild/GivenMSBuildLogger.cs | 96 ---- .../Convert/DotnetProjectConvertTests.cs | 44 ++ .../CommandTests/Run/RunFileTests.cs | 224 ++++++++ src/source-manifest.json | 4 +- 85 files changed, 1336 insertions(+), 763 deletions(-) delete mode 100644 src/sdk/src/Layout/redist/dnx.ps1 diff --git a/src/sdk/NuGet.config b/src/sdk/NuGet.config index 09870da2888..4303832450f 100644 --- a/src/sdk/NuGet.config +++ b/src/sdk/NuGet.config @@ -3,6 +3,8 @@ + + diff --git a/src/sdk/eng/Version.Details.props b/src/sdk/eng/Version.Details.props index 9fa33977310..4189c1aaab8 100644 --- a/src/sdk/eng/Version.Details.props +++ b/src/sdk/eng/Version.Details.props @@ -6,142 +6,142 @@ This file should be imported by eng/Versions.props - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-preview.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 18.0.0-preview-25467-107 - 18.0.0-preview-25467-107 - 7.0.0-preview.2.46807 - 10.0.0-beta.25467.107 - 5.0.0-2.25467.107 - 5.0.0-2.25467.107 - 5.0.0-2.25467.107 - 5.0.0-2.25467.107 - 5.0.0-2.25467.107 - 5.0.0-2.25467.107 - 5.0.0-2.25467.107 - 10.0.0-preview.25467.107 - 5.0.0-2.25467.107 - 5.0.0-2.25467.107 - 2.0.0-preview.1.25467.107 - 2.2.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 14.0.100-rc2.25467.107 - 10.0.0-rc.2.25467.107 - 5.0.0-2.25467.107 - 5.0.0-2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-preview.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 18.0.0-preview-25509-106 + 18.0.0-preview-25509-106 + 7.0.0-rc.1006 + 10.0.0-beta.25509.106 + 5.0.0-2.25509.106 + 5.0.0-2.25509.106 + 5.0.0-2.25509.106 + 5.0.0-2.25509.106 + 5.0.0-2.25509.106 + 5.0.0-2.25509.106 + 5.0.0-2.25509.106 + 10.0.0-preview.25509.106 + 5.0.0-2.25509.106 + 5.0.0-2.25509.106 + 2.0.0-preview.1.25509.106 + 2.2.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 14.0.100-rc2.25509.106 + 10.0.0-rtm.25509.106 + 5.0.0-2.25509.106 + 5.0.0-2.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 10.0.0-preview.7.25377.103 - 10.0.0-preview.25467.107 - 10.0.0-rc.2.25467.107 - 18.0.0-preview-25467-107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.0-beta.25467.107 - 10.0.100-rc.2.25467.107 - 10.0.100-rc.2.25467.107 - 10.0.100-rc.2.25467.107 - 10.0.100-rc.2.25467.107 - 10.0.100-rc.2.25467.107 - 10.0.100-rc.2.25467.107 - 10.0.100-rc.2.25467.107 - 10.0.100-rc.2.25467.107 - 10.0.100-rc.2.25467.107 - 18.0.0-preview-25467-107 - 18.0.0-preview-25467-107 - 3.2.0-preview.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 7.0.0-preview.2.46807 - 10.0.0-rc.2.25467.107 - 2.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 - 10.0.0-rc.2.25467.107 + 10.0.0-preview.25509.106 + 10.0.0-rtm.25509.106 + 18.0.0-release-25509-106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.100-rtm.25509.106 + 10.0.100-rtm.25509.106 + 10.0.100-rtm.25509.106 + 10.0.100-rtm.25509.106 + 10.0.100-rtm.25509.106 + 10.0.100-rtm.25509.106 + 10.0.100-rtm.25509.106 + 10.0.100-rtm.25509.106 + 10.0.100-rtm.25509.106 + 18.0.0-release-25509-106 + 18.0.0-release-25509-106 + 3.2.0-preview.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 10.0.0-rtm.25509.106 + 2.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 2.1.0 - 1.9.0-preview.25475.1 - 3.11.0-preview.25475.1 + 2.1.0-preview.25508.5 + 4.1.0-preview.25508.5 diff --git a/src/sdk/eng/Version.Details.xml b/src/sdk/eng/Version.Details.xml index 6f095d0867f..4510cfb93ad 100644 --- a/src/sdk/eng/Version.Details.xml +++ b/src/sdk/eng/Version.Details.xml @@ -1,62 +1,62 @@ - + - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac @@ -68,166 +68,166 @@ https://github.com/dotnet/dotnet 6a953e76162f3f079405f80e28664fa51b136740 - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/microsoft/testfx - 74721fc4a96eefb3b757e3ffacaae1fdcbe7a0f8 + 9866a77221b818a70721106b9622eac95f81adec - + https://github.com/microsoft/testfx - 74721fc4a96eefb3b757e3ffacaae1fdcbe7a0f8 + 9866a77221b818a70721106b9622eac95f81adec - + https://github.com/dotnet/dotnet - e533cfad385ba4f0ec96e35ad3d485dc13581906 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac diff --git a/src/sdk/eng/Versions.props b/src/sdk/eng/Versions.props index ca336803c73..134ef99b37b 100644 --- a/src/sdk/eng/Versions.props +++ b/src/sdk/eng/Versions.props @@ -38,8 +38,8 @@ 36 20 - 18 - 7 + 19 + 8 <_NET70ILLinkPackVersion>7.0.100-1.23211.1 diff --git a/src/sdk/eng/common/core-templates/job/publish-build-assets.yml b/src/sdk/eng/common/core-templates/job/publish-build-assets.yml index 348cd16376f..37dff559fc1 100644 --- a/src/sdk/eng/common/core-templates/job/publish-build-assets.yml +++ b/src/sdk/eng/common/core-templates/job/publish-build-assets.yml @@ -40,6 +40,8 @@ parameters: repositoryAlias: self + officialBuildId: '' + jobs: - job: Asset_Registry_Publish @@ -62,6 +64,11 @@ jobs: value: false # unconditional - needed for logs publishing (redactor tool version) - template: /eng/common/core-templates/post-build/common-variables.yml + - name: OfficialBuildId + ${{ if ne(parameters.officialBuildId, '') }}: + value: ${{ parameters.officialBuildId }} + ${{ else }}: + value: $(Build.BuildNumber) pool: # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) @@ -124,7 +131,7 @@ jobs: /p:ManifestsPath='$(Build.StagingDirectory)/AssetManifests' /p:IsAssetlessBuild=${{ parameters.isAssetlessBuild }} /p:MaestroApiEndpoint=https://maestro.dot.net - /p:OfficialBuildId=$(Build.BuildNumber) + /p:OfficialBuildId=$(OfficialBuildId) condition: ${{ parameters.condition }} continueOnError: ${{ parameters.continueOnError }} diff --git a/src/sdk/eng/common/core-templates/jobs/jobs.yml b/src/sdk/eng/common/core-templates/jobs/jobs.yml index b637cb6e948..01ada747665 100644 --- a/src/sdk/eng/common/core-templates/jobs/jobs.yml +++ b/src/sdk/eng/common/core-templates/jobs/jobs.yml @@ -44,6 +44,7 @@ parameters: artifacts: {} is1ESPipeline: '' repositoryAlias: self + officialBuildId: '' # Internal resources (telemetry, microbuild) can only be accessed from non-public projects, # and some (Microbuild) should only be applied to non-PR cases for internal builds. @@ -116,3 +117,4 @@ jobs: artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} signingValidationAdditionalParameters: ${{ parameters.signingValidationAdditionalParameters }} repositoryAlias: ${{ parameters.repositoryAlias }} + officialBuildId: ${{ parameters.officialBuildId }} diff --git a/src/sdk/eng/common/post-build/nuget-verification.ps1 b/src/sdk/eng/common/post-build/nuget-verification.ps1 index a365194a938..ac5c69ffcac 100644 --- a/src/sdk/eng/common/post-build/nuget-verification.ps1 +++ b/src/sdk/eng/common/post-build/nuget-verification.ps1 @@ -30,7 +30,7 @@ [CmdletBinding(PositionalBinding = $false)] param( [string]$NuGetExePath, - [string]$PackageSource = "https://api.nuget.org/v3/index.json", + [string]$PackageSource = "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json", [string]$DownloadPath, [Parameter(ValueFromRemainingArguments = $true)] [string[]]$args diff --git a/src/sdk/global.json b/src/sdk/global.json index cf8f1c01329..cf7985786d3 100644 --- a/src/sdk/global.json +++ b/src/sdk/global.json @@ -21,8 +21,8 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25467.107", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25467.107", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25509.106", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25509.106", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.WixToolset.Sdk": "5.0.2-dotnet.2737382" diff --git a/src/sdk/src/BuiltInTools/DotNetDeltaApplier/PipeListener.cs b/src/sdk/src/BuiltInTools/DotNetDeltaApplier/PipeListener.cs index d596594e551..6110f0fa631 100644 --- a/src/sdk/src/BuiltInTools/DotNetDeltaApplier/PipeListener.cs +++ b/src/sdk/src/BuiltInTools/DotNetDeltaApplier/PipeListener.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.IO.Pipes; using System.Reflection; using System.Runtime.Loader; @@ -9,6 +10,17 @@ namespace Microsoft.DotNet.HotReload; internal sealed class PipeListener(string pipeName, IHotReloadAgent agent, Action log, int connectionTimeoutMS = 5000) { + /// + /// Messages to the client sent after the initial is sent + /// need to be sent while holding this lock in order to synchronize + /// 1) responses to requests received from the client (e.g. ) or + /// 2) notifications sent to the client that may be triggered at arbitrary times (e.g. ). + /// + private readonly SemaphoreSlim _messageToClientLock = new(initialCount: 1); + + // Not-null once initialized: + private NamedPipeClientStream? _pipeClient; + public Task Listen(CancellationToken cancellationToken) { // Connect to the pipe synchronously. @@ -21,23 +33,23 @@ public Task Listen(CancellationToken cancellationToken) log($"Connecting to hot-reload server via pipe {pipeName}"); - var pipeClient = new NamedPipeClientStream(serverName: ".", pipeName, PipeDirection.InOut, PipeOptions.CurrentUserOnly | PipeOptions.Asynchronous); + _pipeClient = new NamedPipeClientStream(serverName: ".", pipeName, PipeDirection.InOut, PipeOptions.CurrentUserOnly | PipeOptions.Asynchronous); try { - pipeClient.Connect(connectionTimeoutMS); + _pipeClient.Connect(connectionTimeoutMS); log("Connected."); } catch (TimeoutException) { log($"Failed to connect in {connectionTimeoutMS}ms."); - pipeClient.Dispose(); + _pipeClient.Dispose(); return Task.CompletedTask; } try { // block execution of the app until initial updates are applied: - InitializeAsync(pipeClient, cancellationToken).GetAwaiter().GetResult(); + InitializeAsync(cancellationToken).GetAwaiter().GetResult(); } catch (Exception e) { @@ -46,7 +58,7 @@ public Task Listen(CancellationToken cancellationToken) log(e.Message); } - pipeClient.Dispose(); + _pipeClient.Dispose(); agent.Dispose(); return Task.CompletedTask; @@ -56,7 +68,7 @@ public Task Listen(CancellationToken cancellationToken) { try { - await ReceiveAndApplyUpdatesAsync(pipeClient, initialUpdates: false, cancellationToken); + await ReceiveAndApplyUpdatesAsync(initialUpdates: false, cancellationToken); } catch (Exception e) when (e is not OperationCanceledException) { @@ -64,40 +76,44 @@ public Task Listen(CancellationToken cancellationToken) } finally { - pipeClient.Dispose(); + _pipeClient.Dispose(); agent.Dispose(); } }, cancellationToken); } - private async Task InitializeAsync(NamedPipeClientStream pipeClient, CancellationToken cancellationToken) + private async Task InitializeAsync(CancellationToken cancellationToken) { + Debug.Assert(_pipeClient != null); + agent.Reporter.Report("Writing capabilities: " + agent.Capabilities, AgentMessageSeverity.Verbose); var initPayload = new ClientInitializationResponse(agent.Capabilities); - await initPayload.WriteAsync(pipeClient, cancellationToken); + await initPayload.WriteAsync(_pipeClient, cancellationToken); // Apply updates made before this process was launched to avoid executing unupdated versions of the affected modules. // We should only receive ManagedCodeUpdate when when the debugger isn't attached, // otherwise the initialization should send InitialUpdatesCompleted immediately. // The debugger itself applies these updates when launching process with the debugger attached. - await ReceiveAndApplyUpdatesAsync(pipeClient, initialUpdates: true, cancellationToken); + await ReceiveAndApplyUpdatesAsync(initialUpdates: true, cancellationToken); } - private async Task ReceiveAndApplyUpdatesAsync(NamedPipeClientStream pipeClient, bool initialUpdates, CancellationToken cancellationToken) + private async Task ReceiveAndApplyUpdatesAsync(bool initialUpdates, CancellationToken cancellationToken) { - while (pipeClient.IsConnected) + Debug.Assert(_pipeClient != null); + + while (_pipeClient.IsConnected) { - var payloadType = (RequestType)await pipeClient.ReadByteAsync(cancellationToken); + var payloadType = (RequestType)await _pipeClient.ReadByteAsync(cancellationToken); switch (payloadType) { case RequestType.ManagedCodeUpdate: - await ReadAndApplyManagedCodeUpdateAsync(pipeClient, cancellationToken); + await ReadAndApplyManagedCodeUpdateAsync(cancellationToken); break; case RequestType.StaticAssetUpdate: - await ReadAndApplyStaticAssetUpdateAsync(pipeClient, cancellationToken); + await ReadAndApplyStaticAssetUpdateAsync(cancellationToken); break; case RequestType.InitialUpdatesCompleted when initialUpdates: @@ -110,11 +126,11 @@ private async Task ReceiveAndApplyUpdatesAsync(NamedPipeClientStream pipeClient, } } - private async ValueTask ReadAndApplyManagedCodeUpdateAsync( - NamedPipeClientStream pipeClient, - CancellationToken cancellationToken) + private async ValueTask ReadAndApplyManagedCodeUpdateAsync(CancellationToken cancellationToken) { - var request = await ManagedCodeUpdateRequest.ReadAsync(pipeClient, cancellationToken); + Debug.Assert(_pipeClient != null); + + var request = await ManagedCodeUpdateRequest.ReadAsync(_pipeClient, cancellationToken); bool success; try @@ -131,15 +147,14 @@ private async ValueTask ReadAndApplyManagedCodeUpdateAsync( var logEntries = agent.Reporter.GetAndClearLogEntries(request.ResponseLoggingLevel); - var response = new UpdateResponse(logEntries, success); - await response.WriteAsync(pipeClient, cancellationToken); + await SendResponseAsync(new UpdateResponse(logEntries, success), cancellationToken); } - private async ValueTask ReadAndApplyStaticAssetUpdateAsync( - NamedPipeClientStream pipeClient, - CancellationToken cancellationToken) + private async ValueTask ReadAndApplyStaticAssetUpdateAsync(CancellationToken cancellationToken) { - var request = await StaticAssetUpdateRequest.ReadAsync(pipeClient, cancellationToken); + Debug.Assert(_pipeClient != null); + + var request = await StaticAssetUpdateRequest.ReadAsync(_pipeClient, cancellationToken); try { @@ -155,8 +170,22 @@ private async ValueTask ReadAndApplyStaticAssetUpdateAsync( // Updating static asset only invokes ContentUpdate metadata update handlers. // Failures of these handlers are reported to the log and ignored. // Therefore, this request always succeeds. - var response = new UpdateResponse(logEntries, success: true); + await SendResponseAsync(new UpdateResponse(logEntries, success: true), cancellationToken); + } - await response.WriteAsync(pipeClient, cancellationToken); + internal async ValueTask SendResponseAsync(T response, CancellationToken cancellationToken) + where T : IResponse + { + Debug.Assert(_pipeClient != null); + try + { + await _messageToClientLock.WaitAsync(cancellationToken); + await _pipeClient.WriteAsync((byte)response.Type, cancellationToken); + await response.WriteAsync(_pipeClient, cancellationToken); + } + finally + { + _messageToClientLock.Release(); + } } } diff --git a/src/sdk/src/BuiltInTools/DotNetDeltaApplier/StartupHook.cs b/src/sdk/src/BuiltInTools/DotNetDeltaApplier/StartupHook.cs index 28890852482..03c7b04a4fe 100644 --- a/src/sdk/src/BuiltInTools/DotNetDeltaApplier/StartupHook.cs +++ b/src/sdk/src/BuiltInTools/DotNetDeltaApplier/StartupHook.cs @@ -40,14 +40,49 @@ public static void Initialize() RegisterSignalHandlers(); - var agent = new HotReloadAgent(assemblyResolvingHandler: (_, args) => - { - Log($"Resolving '{args.Name}, Version={args.Version}'"); - var path = Path.Combine(processDir, args.Name + ".dll"); - return File.Exists(path) ? AssemblyLoadContext.Default.LoadFromAssemblyPath(path) : null; - }); + PipeListener? listener = null; + + var agent = new HotReloadAgent( + assemblyResolvingHandler: (_, args) => + { + Log($"Resolving '{args.Name}, Version={args.Version}'"); + var path = Path.Combine(processDir, args.Name + ".dll"); + return File.Exists(path) ? AssemblyLoadContext.Default.LoadFromAssemblyPath(path) : null; + }, + hotReloadExceptionCreateHandler: (code, message) => + { + // Continue executing the code if the debugger is attached. + // It will throw the exception and the debugger will handle it. + if (Debugger.IsAttached) + { + return; + } + + Debug.Assert(listener != null); + Log($"Runtime rude edit detected: '{message}'"); + + SendAndForgetAsync().Wait(); + + // Handle Ctrl+C to terminate gracefully: + Console.CancelKeyPress += (_, _) => Environment.Exit(0); + + // wait for the process to be terminated by the Hot Reload client (other threads might still execute): + Thread.Sleep(Timeout.Infinite); + + async Task SendAndForgetAsync() + { + try + { + await listener.SendResponseAsync(new HotReloadExceptionCreatedNotification(code, message), CancellationToken.None); + } + catch + { + // do not crash the app + } + } + }); - var listener = new PipeListener(s_namedPipeName, agent, Log); + listener = new PipeListener(s_namedPipeName, agent, Log); // fire and forget: _ = listener.Listen(CancellationToken.None); diff --git a/src/sdk/src/BuiltInTools/HotReloadAgent.PipeRpc/NamedPipeContract.cs b/src/sdk/src/BuiltInTools/HotReloadAgent.PipeRpc/NamedPipeContract.cs index 66766e1c74e..dfa0158c53c 100644 --- a/src/sdk/src/BuiltInTools/HotReloadAgent.PipeRpc/NamedPipeContract.cs +++ b/src/sdk/src/BuiltInTools/HotReloadAgent.PipeRpc/NamedPipeContract.cs @@ -12,23 +12,39 @@ namespace Microsoft.DotNet.HotReload; -internal interface IRequest +internal interface IMessage { - RequestType Type { get; } ValueTask WriteAsync(Stream stream, CancellationToken cancellationToken); } +internal interface IRequest : IMessage +{ + RequestType Type { get; } +} + +internal interface IResponse : IMessage +{ + ResponseType Type { get; } +} + internal interface IUpdateRequest : IRequest { } -internal enum RequestType +internal enum RequestType : byte { ManagedCodeUpdate = 1, StaticAssetUpdate = 2, InitialUpdatesCompleted = 3, } +internal enum ResponseType : byte +{ + InitializationResponse = 1, + UpdateResponse = 2, + HotReloadExceptionNotification = 3, +} + internal readonly struct ManagedCodeUpdateRequest(IReadOnlyList updates, ResponseLoggingLevel responseLoggingLevel) : IUpdateRequest { private const byte Version = 4; @@ -81,8 +97,10 @@ public static async ValueTask ReadAsync(Stream stream, } } -internal readonly struct UpdateResponse(IReadOnlyCollection<(string message, AgentMessageSeverity severity)> log, bool success) +internal readonly struct UpdateResponse(IReadOnlyCollection<(string message, AgentMessageSeverity severity)> log, bool success) : IResponse { + public ResponseType Type => ResponseType.UpdateResponse; + public async ValueTask WriteAsync(Stream stream, CancellationToken cancellationToken) { await stream.WriteAsync(success, cancellationToken); @@ -116,10 +134,12 @@ public async ValueTask WriteAsync(Stream stream, CancellationToken cancellationT } } -internal readonly struct ClientInitializationResponse(string capabilities) +internal readonly struct ClientInitializationResponse(string capabilities) : IResponse { private const byte Version = 0; + public ResponseType Type => ResponseType.InitializationResponse; + public string Capabilities { get; } = capabilities; public async ValueTask WriteAsync(Stream stream, CancellationToken cancellationToken) @@ -141,6 +161,26 @@ public static async ValueTask ReadAsync(Stream str } } +internal readonly struct HotReloadExceptionCreatedNotification(int code, string message) : IResponse +{ + public ResponseType Type => ResponseType.HotReloadExceptionNotification; + public int Code => code; + public string Message => message; + + public async ValueTask WriteAsync(Stream stream, CancellationToken cancellationToken) + { + await stream.WriteAsync(code, cancellationToken); + await stream.WriteAsync(message, cancellationToken); + } + + public static async ValueTask ReadAsync(Stream stream, CancellationToken cancellationToken) + { + var code = await stream.ReadInt32Async(cancellationToken); + var message = await stream.ReadStringAsync(cancellationToken); + return new HotReloadExceptionCreatedNotification(code, message); + } +} + internal readonly struct StaticAssetUpdateRequest( RuntimeStaticAssetUpdate update, ResponseLoggingLevel responseLoggingLevel) : IUpdateRequest diff --git a/src/sdk/src/BuiltInTools/HotReloadAgent.WebAssembly.Browser/WebAssemblyHotReload.cs b/src/sdk/src/BuiltInTools/HotReloadAgent.WebAssembly.Browser/WebAssemblyHotReload.cs index 2169ef3dbd9..1aad8e47f07 100644 --- a/src/sdk/src/BuiltInTools/HotReloadAgent.WebAssembly.Browser/WebAssemblyHotReload.cs +++ b/src/sdk/src/BuiltInTools/HotReloadAgent.WebAssembly.Browser/WebAssemblyHotReload.cs @@ -71,7 +71,8 @@ public static async Task InitializeAsync(string baseUri) { s_initialized = true; - var agent = new HotReloadAgent(assemblyResolvingHandler: null); + // TODO: Implement hotReloadExceptionCreateHandler: https://github.com/dotnet/sdk/issues/51056 + var agent = new HotReloadAgent(assemblyResolvingHandler: null, hotReloadExceptionCreateHandler: null); var existingAgent = Interlocked.CompareExchange(ref s_hotReloadAgent, agent, null); if (existingAgent != null) diff --git a/src/sdk/src/BuiltInTools/HotReloadAgent/HotReloadAgent.cs b/src/sdk/src/BuiltInTools/HotReloadAgent/HotReloadAgent.cs index 4114bed5e6f..f6418014407 100644 --- a/src/sdk/src/BuiltInTools/HotReloadAgent/HotReloadAgent.cs +++ b/src/sdk/src/BuiltInTools/HotReloadAgent/HotReloadAgent.cs @@ -38,11 +38,16 @@ internal sealed class HotReloadAgent : IDisposable, IHotReloadAgent private Func? _assemblyResolvingHandlerToInstall; private Func? _installedAssemblyResolvingHandler; - public HotReloadAgent(Func? assemblyResolvingHandler) + // handler to install to HotReloadException.Created: + private Action? _hotReloadExceptionCreateHandler; + + public HotReloadAgent( + Func? assemblyResolvingHandler, + Action? hotReloadExceptionCreateHandler) { _metadataUpdateHandlerInvoker = new(Reporter); _assemblyResolvingHandlerToInstall = assemblyResolvingHandler; - + _hotReloadExceptionCreateHandler = hotReloadExceptionCreateHandler; GetUpdaterMethodsAndCapabilities(out _applyUpdate, out _capabilities); AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad; @@ -148,11 +153,69 @@ public void ApplyManagedCodeUpdates(IEnumerable update cachedModuleUpdates.Add(update); } - _metadataUpdateHandlerInvoker.MetadataUpdated(GetMetadataUpdateTypes(updates)); + var updatedTypes = GetMetadataUpdateTypes(updates); + + InstallHotReloadExceptionCreatedHandler(updatedTypes); + + _metadataUpdateHandlerInvoker.MetadataUpdated(updatedTypes); Reporter.Report("Updates applied.", AgentMessageSeverity.Verbose); } + private void InstallHotReloadExceptionCreatedHandler(Type[] types) + { + if (_hotReloadExceptionCreateHandler is null) + { + // already installed or not available + return; + } + + var exceptionType = types.FirstOrDefault(static t => t.FullName == "System.Runtime.CompilerServices.HotReloadException"); + if (exceptionType == null) + { + return; + } + + var handler = Interlocked.Exchange(ref _hotReloadExceptionCreateHandler, null); + if (handler == null) + { + // already installed or not available + return; + } + + // HotReloadException has a private static field Action Created, unless emitted by previous versions of the compiler: + // See https://github.com/dotnet/roslyn/blob/06f2643e1268e4a7fcdf1221c052f9c8cce20b60/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs#L29 + var createdField = exceptionType.GetField("Created", BindingFlags.Static | BindingFlags.NonPublic); + var codeField = exceptionType.GetField("Code", BindingFlags.Public | BindingFlags.Instance); + if (createdField == null || codeField == null) + { + Reporter.Report($"Failed to install HotReloadException handler: not supported by the compiler", AgentMessageSeverity.Verbose); + return; + } + + try + { + createdField.SetValue(null, new Action(e => + { + try + { + handler(codeField.GetValue(e) is int code ? code : 0, e.Message); + } + catch + { + // do not crash the app + } + })); + } + catch (Exception e) + { + Reporter.Report($"Failed to install HotReloadException handler: {e.Message}", AgentMessageSeverity.Verbose); + return; + } + + Reporter.Report($"HotReloadException handler installed.", AgentMessageSeverity.Verbose); + } + private Type[] GetMetadataUpdateTypes(IEnumerable updates) { List? types = null; diff --git a/src/sdk/src/BuiltInTools/HotReloadAgent/MetadataUpdateHandlerInvoker.cs b/src/sdk/src/BuiltInTools/HotReloadAgent/MetadataUpdateHandlerInvoker.cs index 952ba4866de..e841af26513 100644 --- a/src/sdk/src/BuiltInTools/HotReloadAgent/MetadataUpdateHandlerInvoker.cs +++ b/src/sdk/src/BuiltInTools/HotReloadAgent/MetadataUpdateHandlerInvoker.cs @@ -110,7 +110,7 @@ private RegisteredActions GetActions() } /// - /// Invokes all registered mtadata update handlers. + /// Invokes all registered metadata update handlers. /// internal void MetadataUpdated(Type[] updatedTypes) { diff --git a/src/sdk/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs b/src/sdk/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs index 1063ba1635f..c7b325a4c34 100644 --- a/src/sdk/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs +++ b/src/sdk/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs @@ -28,6 +28,9 @@ internal sealed class DefaultHotReloadClient(ILogger logger, ILogger agentLogger private NamedPipeServerStream? _pipe; private bool _managedCodeUpdateFailedOrCancelled; + // The status of the last update response. + private TaskCompletionSource _updateStatusSource = new(); + public override void Dispose() { DisposePipe(); @@ -75,24 +78,65 @@ async Task> ConnectAsync() var capabilities = (await ClientInitializationResponse.ReadAsync(_pipe, cancellationToken)).Capabilities; Logger.Log(LogEvents.Capabilities, capabilities); + + // fire and forget: + _ = ListenForResponsesAsync(cancellationToken); + return [.. capabilities.Split(' ')]; } - catch (EndOfStreamException) + catch (Exception e) when (e is not OperationCanceledException) { - // process terminated before capabilities sent: + ReportPipeReadException(e, "capabilities", cancellationToken); return []; } - catch (Exception e) when (e is not OperationCanceledException) + } + } + + private void ReportPipeReadException(Exception e, string responseType, CancellationToken cancellationToken) + { + // Don't report a warning when cancelled or the pipe has been disposed. The process has terminated or the host is shutting down in that case. + // Best effort: There is an inherent race condition due to time between the process exiting and the cancellation token triggering. + if (e is ObjectDisposedException or EndOfStreamException || cancellationToken.IsCancellationRequested) + { + return; + } + + Logger.LogError("Failed to read {ResponseType} from the pipe: {Message}", responseType, e.Message); + } + + private async Task ListenForResponsesAsync(CancellationToken cancellationToken) + { + Debug.Assert(_pipe != null); + + try + { + while (!cancellationToken.IsCancellationRequested) { - // pipe might throw another exception when forcibly closed on process termination: - if (!cancellationToken.IsCancellationRequested) + var type = (ResponseType)await _pipe.ReadByteAsync(cancellationToken); + + switch (type) { - Logger.LogError("Failed to read capabilities: {Message}", e.Message); + case ResponseType.UpdateResponse: + // update request can't be issued again until the status is read and a new source is created: + _updateStatusSource.SetResult(await ReadUpdateResponseAsync(cancellationToken)); + break; + + case ResponseType.HotReloadExceptionNotification: + var notification = await HotReloadExceptionCreatedNotification.ReadAsync(_pipe, cancellationToken); + RuntimeRudeEditDetected(notification.Code, notification.Message); + break; + + default: + // can't continue, the pipe is in undefined state: + Logger.LogError("Unexpected response received from the agent: {ResponseType}", type); + return; } - - return []; } } + catch (Exception e) + { + ReportPipeReadException(e, "response", cancellationToken); + } } [MemberNotNull(nameof(_capabilitiesTask))] @@ -278,6 +322,13 @@ async ValueTask WriteRequestAsync(CancellationToken cancellationToken) } private async ValueTask ReceiveUpdateResponseAsync(CancellationToken cancellationToken) + { + var result = await _updateStatusSource.Task; + _updateStatusSource = new TaskCompletionSource(); + return result; + } + + private async ValueTask ReadUpdateResponseAsync(CancellationToken cancellationToken) { // Should be initialized: Debug.Assert(_pipe != null); diff --git a/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClient.cs b/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClient.cs index e5efa4db2a7..2a563419e4f 100644 --- a/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClient.cs +++ b/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClient.cs @@ -32,6 +32,11 @@ internal abstract class HotReloadClient(ILogger logger, ILogger agentLogger) : I private readonly object _pendingUpdatesGate = new(); private Task _pendingUpdates = Task.CompletedTask; + /// + /// Invoked when a rude edit is detected at runtime. + /// + public event Action? OnRuntimeRudeEdit; + // for testing internal Task PendingUpdates => _pendingUpdates; @@ -79,6 +84,9 @@ internal Task PendingUpdates /// public abstract void Dispose(); + protected void RuntimeRudeEditDetected(int errorCode, string message) + => OnRuntimeRudeEdit?.Invoke(errorCode, message); + public static void ReportLogEntry(ILogger logger, string message, AgentMessageSeverity severity) { var level = severity switch diff --git a/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClients.cs b/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClients.cs index 58676fdcf5d..fcf541045fc 100644 --- a/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClients.cs +++ b/src/sdk/src/BuiltInTools/HotReloadClient/HotReloadClients.cs @@ -37,6 +37,28 @@ public void Dispose() public AbstractBrowserRefreshServer? BrowserRefreshServer => browserRefreshServer; + /// + /// Invoked when a rude edit is detected at runtime. + /// May be invoked multiple times, by each client. + /// + public event Action OnRuntimeRudeEdit + { + add + { + foreach (var (client, _) in clients) + { + client.OnRuntimeRudeEdit += value; + } + } + remove + { + foreach (var (client, _) in clients) + { + client.OnRuntimeRudeEdit -= value; + } + } + } + /// /// All clients share the same loggers. /// @@ -90,7 +112,8 @@ public async ValueTask> GetUpdateCapabilitiesAsync(Cancel } /// Cancellation token. The cancellation should trigger on process terminatation. - public async ValueTask ApplyManagedCodeUpdatesAsync(ImmutableArray updates, bool isProcessSuspended, CancellationToken cancellationToken) + /// True if the updates are initial updates applied automatically when a process starts. + public async ValueTask ApplyManagedCodeUpdatesAsync(ImmutableArray updates, bool isProcessSuspended, bool isInitial, CancellationToken cancellationToken) { var anyFailure = false; @@ -135,9 +158,13 @@ public async ValueTask ApplyManagedCodeUpdatesAsync(ImmutableArray + { + // fire and forget: + _ = HandleRuntimeRudeEditAsync(runningProject, message, cancellationToken); + }; + // Notifies the agent that it can unblock the execution of the process: await clients.InitialUpdatesAppliedAsync(processCommunicationCancellationToken); @@ -215,6 +221,41 @@ public async ValueTask StartSessionAsync(CancellationToken cancellationToken) } } + private async Task HandleRuntimeRudeEditAsync(RunningProject runningProject, string rudeEditMessage, CancellationToken cancellationToken) + { + var logger = runningProject.Clients.ClientLogger; + + try + { + // Always auto-restart on runtime rude edits regardless of the settings. + // Since there is no debugger attached the process would crash on an unhandled HotReloadException if + // we let it continue executing. + logger.LogWarning(rudeEditMessage); + logger.Log(MessageDescriptor.RestartingApplication); + + if (!runningProject.InitiateRestart()) + { + // Already in the process of restarting, possibly because of another runtime rude edit. + return; + } + + await runningProject.Clients.ReportCompilationErrorsInApplicationAsync([rudeEditMessage, MessageDescriptor.RestartingApplication.GetMessage()], cancellationToken); + + // Terminate the process. + await runningProject.TerminateAsync(); + + // Creates a new running project and launches it: + await runningProject.RestartOperation(cancellationToken); + } + catch (Exception e) + { + if (e is not OperationCanceledException) + { + logger.LogError("Failed to handle runtime rude edit: {Exception}", e.ToString()); + } + } + } + private ImmutableArray GetAggregateCapabilities() { var capabilities = _runningProjects @@ -329,7 +370,7 @@ await ForEachProjectAsync(projectsToUpdate, async (runningProject, cancellationT try { using var processCommunicationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(runningProject.ProcessExitedCancellationToken, cancellationToken); - await runningProject.Clients.ApplyManagedCodeUpdatesAsync(ToManagedCodeUpdates(updates), isProcessSuspended: false, processCommunicationCancellationSource.Token); + await runningProject.Clients.ApplyManagedCodeUpdatesAsync(ToManagedCodeUpdates(updates), isProcessSuspended: false, isInitial: false, processCommunicationCancellationSource.Token); } catch (OperationCanceledException) when (runningProject.ProcessExitedCancellationToken.IsCancellationRequested && !cancellationToken.IsCancellationRequested) { @@ -583,7 +624,7 @@ internal async ValueTask> TerminateNonRootProcess // Do not terminate root process at this time - it would signal the cancellation token we are currently using. // The process will be restarted later on. // Wait for all processes to exit to release their resources, so we can rebuild. - await Task.WhenAll(projectsToRestart.Where(p => !p.Options.IsRootProject).Select(p => p.TerminateAsync(isRestarting: true))).WaitAsync(cancellationToken); + await Task.WhenAll(projectsToRestart.Where(p => !p.Options.IsRootProject).Select(p => p.TerminateForRestartAsync())).WaitAsync(cancellationToken); return projectsToRestart; } diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs b/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs index 6f4b8803ed9..38e313f6f74 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs @@ -128,7 +128,7 @@ public async Task WatchAsync(CancellationToken shutdownCancellationToken) rootProcessTerminationSource, onOutput: null, onExit: null, - restartOperation: new RestartOperation(_ => throw new InvalidOperationException("Root project shouldn't be restarted")), + restartOperation: new RestartOperation(_ => default), // the process will automatically restart iterationCancellationToken); if (rootRunningProject == null) @@ -531,7 +531,7 @@ async Task> CaptureChangedFilesSnapshot(ImmutableArra if (rootRunningProject != null) { - await rootRunningProject.TerminateAsync(isRestarting: false); + await rootRunningProject.TerminateAsync(); } if (runtimeProcessLauncher != null) @@ -541,7 +541,8 @@ async Task> CaptureChangedFilesSnapshot(ImmutableArra if (waitForFileChangeBeforeRestarting && !shutdownCancellationToken.IsCancellationRequested && - !forceRestartCancellationSource.IsCancellationRequested) + !forceRestartCancellationSource.IsCancellationRequested && + rootRunningProject?.IsRestarting != true) { using var shutdownOrForcedRestartSource = CancellationTokenSource.CreateLinkedTokenSource(shutdownCancellationToken, forceRestartCancellationSource.Token); await WaitForFileChangeBeforeRestarting(fileWatcher, evaluationResult, shutdownOrForcedRestartSource.Token); diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/Process/RunningProject.cs b/src/sdk/src/BuiltInTools/dotnet-watch/Process/RunningProject.cs index c2662ceec1f..8f5bfe94b00 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/Process/RunningProject.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/Process/RunningProject.cs @@ -41,8 +41,9 @@ internal sealed class RunningProject( /// Set to true when the process termination is being requested so that it can be restarted within /// the Hot Reload session (i.e. without restarting the root project). /// - public bool IsRestarting { get; private set; } + public bool IsRestarting => _isRestarting != 0; + private volatile int _isRestarting; private volatile bool _isDisposed; /// @@ -81,16 +82,34 @@ public async ValueTask WaitForProcessRunningAsync(CancellationToken cancel } } - public async Task TerminateAsync(bool isRestarting) + /// + /// Terminates the process if it hasn't terminated yet. + /// + public Task TerminateAsync() { - IsRestarting = isRestarting; - if (!_isDisposed) { processTerminationSource.Cancel(); } - return await RunningProcess; + return RunningProcess; + } + + /// + /// Marks the as restarting. + /// Subsequent process termination will be treated as a restart. + /// + /// True if the project hasn't been int restarting state prior the call. + public bool InitiateRestart() + => Interlocked.Exchange(ref _isRestarting, 1) == 0; + + /// + /// Terminates the process in preparation for a restart. + /// + public Task TerminateForRestartAsync() + { + InitiateRestart(); + return TerminateAsync(); } } } diff --git a/src/sdk/src/BuiltInTools/dotnet-watch/UI/IReporter.cs b/src/sdk/src/BuiltInTools/dotnet-watch/UI/IReporter.cs index 3d60e288a97..319fcc1740b 100644 --- a/src/sdk/src/BuiltInTools/dotnet-watch/UI/IReporter.cs +++ b/src/sdk/src/BuiltInTools/dotnet-watch/UI/IReporter.cs @@ -215,6 +215,7 @@ public MessageDescriptor WithSeverityWhen(MessageSeverity severity, bool conditi public static readonly MessageDescriptor RefreshServerRunningAt = Create(LogEvents.RefreshServerRunningAt, Emoji.Default); public static readonly MessageDescriptor ConnectedToRefreshServer = Create(LogEvents.ConnectedToRefreshServer, Emoji.Default); public static readonly MessageDescriptor RestartingApplicationToApplyChanges = Create("Restarting application to apply changes ...", Emoji.Default, MessageSeverity.Output); + public static readonly MessageDescriptor RestartingApplication = Create("Restarting application ...", Emoji.Default, MessageSeverity.Output); public static readonly MessageDescriptor IgnoringChangeInHiddenDirectory = Create("Ignoring change in hidden directory '{0}': {1} '{2}'", Emoji.Watch, MessageSeverity.Verbose); public static readonly MessageDescriptor IgnoringChangeInOutputDirectory = Create("Ignoring change in output directory: {0} '{1}'", Emoji.Watch, MessageSeverity.Verbose); public static readonly MessageDescriptor IgnoringChangeInExcludedFile = Create("Ignoring change in excluded file '{0}': {1}. Path matches {2} glob '{3}' set in '{4}'.", Emoji.Watch, MessageSeverity.Verbose); diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf index ecb19bae658..c65c0e782a6 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + Výsledek analýzy následujícího kódu JSON byl null: {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf index 0b82cc14850..077b39b257a 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + Das Ergebnis der Analyse des folgenden JSON war „null“: {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf index c76d9428883..83e578cc990 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + El resultado del análisis del siguiente JSON fue "null": {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf index 3dd088fe92f..321017f2a61 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + Le résultat de l'analyse du JSON suivant était « null » : {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf index 5022ad18a8c..37c751e7c39 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + Il risultato dell'analisi del file JSON seguente è 'null': {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf index e27c0eea775..58b3201670e 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + 次の JSON の解析結果は 'null' でした: {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf index 28e0b7ef6ea..5367a26984e 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + 다음 JSON을 구문 분석한 결과는 'null'입니다. {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf index edc3a399520..35d4691fba5 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + Wynikiem analizy następującego kodu JSON była wartość „null”: {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf index 22b848dd30e..accfeb0309e 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + O resultado da análise sintática do JSON a seguir foi 'null': {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf index b41a1a5ac24..c5e680a9798 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + Результат разбора следующего JSON оказался равен null: {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf index 158582a214b..ba424b44aa5 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + Aşağıdaki JSON'un ayrıştırma sonucu 'null' idi: {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf index 2df9444a65e..e1820411d6c 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + 解析以下 JSON 会得到 "null": {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf index 1c17c1adc32..5030f71d78c 100644 --- a/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/sdk/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf @@ -854,7 +854,7 @@ The header is followed by the list of parameters and their errors (might be seve The result of parsing the following JSON was 'null': {0} - The result of parsing the following JSON was 'null': + 剖析下列 JSON 的結果為 'null': {0} {0} is the JSON that is being parsed. diff --git a/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs b/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs index 00e73d0db6b..265b1eafbb7 100644 --- a/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs +++ b/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs @@ -119,6 +119,8 @@ public void Initialize(IEventSource eventSource) eventSource.BuildFinished += OnBuildFinished; } + + eventSource.BuildFinished += OnBuildFinished; } catch (Exception) { @@ -133,9 +135,10 @@ private void OnBuildFinished(object sender, BuildFinishedEventArgs e) internal void SendAggregatedEventsOnBuildFinished(ITelemetry? telemetry) { + if (telemetry is null) return; if (_aggregatedEvents.TryGetValue(TaskFactoryTelemetryAggregatedEventName, out var taskFactoryData)) { - var taskFactoryProperties = ConvertToStringDictionary(taskFactoryData); + Dictionary taskFactoryProperties = ConvertToStringDictionary(taskFactoryData); TrackEvent(telemetry, $"msbuild/{TaskFactoryTelemetryAggregatedEventName}", taskFactoryProperties, toBeHashed: [], toBeMeasured: []); _aggregatedEvents.Remove(TaskFactoryTelemetryAggregatedEventName); @@ -143,7 +146,7 @@ internal void SendAggregatedEventsOnBuildFinished(ITelemetry? telemetry) if (_aggregatedEvents.TryGetValue(TasksTelemetryAggregatedEventName, out var tasksData)) { - var tasksProperties = ConvertToStringDictionary(tasksData); + Dictionary tasksProperties = ConvertToStringDictionary(tasksData); TrackEvent(telemetry, $"msbuild/{TasksTelemetryAggregatedEventName}", tasksProperties, toBeHashed: [], toBeMeasured: []); _aggregatedEvents.Remove(TasksTelemetryAggregatedEventName); @@ -163,14 +166,10 @@ internal void SendAggregatedEventsOnBuildFinished(ITelemetry? telemetry) internal void AggregateEvent(TelemetryEventArgs args) { - if (args.EventName == null || args.Properties == null) - { - return; - } - - if (!_aggregatedEvents.TryGetValue(args.EventName, out var eventData)) + if (args.EventName is null) return; + if (!_aggregatedEvents.TryGetValue(args.EventName, out Dictionary? eventData) || eventData is null) { - eventData = []; + eventData = new Dictionary(); _aggregatedEvents[args.EventName] = eventData; } diff --git a/src/sdk/src/Cli/dotnet/Commands/Run/RunCommand.cs b/src/sdk/src/Cli/dotnet/Commands/Run/RunCommand.cs index 635566bf07b..542fc76ffbc 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Run/RunCommand.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Run/RunCommand.cs @@ -6,6 +6,7 @@ using System.CommandLine; using System.CommandLine.Parsing; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Microsoft.Build.Evaluation; using Microsoft.Build.Exceptions; using Microsoft.Build.Execution; @@ -499,6 +500,7 @@ static void InvokeRunArgumentsTarget(ProjectInstance project, bool noBuild, Faca } } + [DoesNotReturn] internal static void ThrowUnableToRunError(ProjectInstance project) { string targetFrameworks = project.GetPropertyValue("TargetFrameworks"); diff --git a/src/sdk/src/Cli/dotnet/Commands/Run/RunProperties.cs b/src/sdk/src/Cli/dotnet/Commands/Run/RunProperties.cs index 81e92cb8831..6972d140ac5 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Run/RunProperties.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Run/RunProperties.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using Microsoft.Build.Execution; using Microsoft.DotNet.Cli.Utils; @@ -19,9 +20,9 @@ internal RunProperties(string command, string? arguments, string? workingDirecto { } - internal static RunProperties FromProject(ProjectInstance project) + internal static bool TryFromProject(ProjectInstance project, [NotNullWhen(returnValue: true)] out RunProperties? result) { - var result = new RunProperties( + result = new RunProperties( Command: project.GetPropertyValue("RunCommand"), Arguments: project.GetPropertyValue("RunArguments"), WorkingDirectory: project.GetPropertyValue("RunWorkingDirectory"), @@ -30,6 +31,17 @@ internal static RunProperties FromProject(ProjectInstance project) TargetFrameworkVersion: project.GetPropertyValue("TargetFrameworkVersion")); if (string.IsNullOrEmpty(result.Command)) + { + result = null; + return false; + } + + return true; + } + + internal static RunProperties FromProject(ProjectInstance project) + { + if (!TryFromProject(project, out var result)) { RunCommand.ThrowUnableToRunError(project); } diff --git a/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs b/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs index 6b99feedd1a..5119a2b579d 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs @@ -354,7 +354,9 @@ public override int Execute() Debug.Assert(buildRequest.ProjectInstance != null); // Cache run info (to avoid re-evaluating the project instance). - cache.CurrentEntry.Run = RunProperties.FromProject(buildRequest.ProjectInstance); + cache.CurrentEntry.Run = RunProperties.TryFromProject(buildRequest.ProjectInstance, out var runProperties) + ? runProperties + : null; if (!MSBuildUtilities.ConvertStringToBool(buildRequest.ProjectInstance.GetPropertyValue(FileBasedProgramCanSkipMSBuild), defaultValue: true)) { @@ -899,7 +901,7 @@ private BuildLevel GetBuildLevel(out CacheInfo cache) { if (!NeedsToBuild(out cache)) { - Reporter.Verbose.WriteLine("No need to build, the output is up to date."); + Reporter.Verbose.WriteLine("No need to build, the output is up to date. Cache: " + ArtifactsPath); return BuildLevel.None; } @@ -1755,8 +1757,8 @@ public readonly struct ParseContext private static (string, string?)? ParseOptionalTwoParts(in ParseContext context, char separator) { - var i = context.DirectiveText.IndexOf(separator, StringComparison.Ordinal); - var firstPart = (i < 0 ? context.DirectiveText : context.DirectiveText.AsSpan(..i)).TrimEnd(); + var separatorIndex = context.DirectiveText.IndexOf(separator, StringComparison.Ordinal); + var firstPart = (separatorIndex < 0 ? context.DirectiveText : context.DirectiveText.AsSpan(..separatorIndex)).TrimEnd(); string directiveKind = context.DirectiveKind; if (firstPart.IsWhiteSpace()) @@ -1770,12 +1772,20 @@ private static (string, string?)? ParseOptionalTwoParts(in ParseContext context, return context.Diagnostics.AddError<(string, string?)?>(context.SourceFile, context.Info.Span, string.Format(CliCommandStrings.InvalidDirectiveName, directiveKind, separator)); } - var secondPart = i < 0 ? [] : context.DirectiveText.AsSpan((i + 1)..).TrimStart(); - if (i < 0 || secondPart.IsWhiteSpace()) + if (separatorIndex < 0) { return (firstPart.ToString(), null); } + var secondPart = context.DirectiveText.AsSpan((separatorIndex + 1)..).TrimStart(); + if (secondPart.IsWhiteSpace()) + { + Debug.Assert(secondPart.Length == 0, + "We have trimmed the second part, so if it's white space, it should be actually empty."); + + return (firstPart.ToString(), string.Empty); + } + return (firstPart.ToString(), secondPart.ToString()); } diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index 10a84c76b1a..17ecd6053ba 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -1164,12 +1164,12 @@ Další informace najdete na https://aka.ms/dotnet-test/mtp. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + Testovací příkaz .NET pro Microsoft.Testing.Platform (vyjádřen výslovný souhlas prostřednictvím souboru global.json). Podporuje jenom Microsoft.Testing.Platform a nepodporuje VSTest. Další informace najdete na https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + Testovací příkaz .NET pro VSTest. Pokud chcete použít Microsoft.Testing.Platform, prostřednictvím souboru global.json vyjádřete výslovný souhlas s příkazem založeným na Microsoft.Testing.Platform. Další informace najdete na https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Nastavte odlišné názvy profilů. duration: - duration: + doba trvání: error: - error: + chyba: @@ -1298,7 +1298,7 @@ Nastavte odlišné názvy profilů. failed: - failed: + neúspěšné: @@ -2699,7 +2699,7 @@ Ve výchozím nastavení je publikována aplikace závislá na architektuře. retried - retried + zkoušeno opakovaně @@ -2983,7 +2983,7 @@ Cílem projektu je více architektur. Pomocí parametru {0} určete, která arch skipped: - skipped: + přeskočeno: @@ -3123,7 +3123,7 @@ Cílem projektu je více architektur. Pomocí parametru {0} určete, která arch succeeded: - succeeded: + úspěšné: @@ -3589,7 +3589,7 @@ příkazu „dotnet tool list“. total: - total: + celkem: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index 70630b7a74b..e2bb95312d1 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -1164,12 +1164,12 @@ Weitere Informationen finden Sie unter https://aka.ms/dotnet-test/mtp. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET-Testbefehl für Microsoft.Testing.Platform (über die Datei „global.json“ aktiviert). Dies unterstützt ausschließlich Microsoft.Testing.Platform und nicht VSTest. Weitere Informationen finden Sie unter https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + .NET-Testbefehl für VSTest. Um Microsoft.Testing.Platform zu verwenden, aktivieren Sie den Microsoft.Testing.Platform-basierten Befehl über global.json. Weitere Informationen finden Sie unter https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Erstellen Sie eindeutige Profilnamen. duration: - duration: + Dauer: error: - error: + Fehler: @@ -1298,7 +1298,7 @@ Erstellen Sie eindeutige Profilnamen. failed: - failed: + fehlgeschlagen: @@ -2699,7 +2699,7 @@ Standardmäßig wird eine Framework-abhängige Anwendung veröffentlicht. retried - retried + Wiederholung @@ -2983,7 +2983,7 @@ Ihr Projekt verwendet mehrere Zielframeworks. Geben Sie über "{0}" an, welches skipped: - skipped: + übersprungen: @@ -3123,7 +3123,7 @@ Ihr Projekt verwendet mehrere Zielframeworks. Geben Sie über "{0}" an, welches succeeded: - succeeded: + erfolgreich: @@ -3589,7 +3589,7 @@ und die zugehörigen Paket-IDs für installierte Tools über den Befehl total: - total: + gesamt: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index 84d3025e048..2446c0253eb 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -1164,12 +1164,12 @@ Consulte https://aka.ms/dotnet-test/mtp para obtener más información. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + Comando de prueba de .NET para Microsoft.Testing.Platform (activado mediante el archivo “global.json”). Solo es compatible con Microsoft.Testing.Platform y no con VSTest. Consulte https://aka.ms/dotnet-test para obtener más información. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + Comando de prueba de .NET para VSTest. Para usar Microsoft.Testing.Platform, actívelo en el comando basado en Microsoft.Testing.Platform mediante global.json. Consulte https://aka.ms/dotnet-test para obtener más información. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Defina nombres de perfiles distintos. duration: - duration: + duración: error: - error: + error: @@ -1298,7 +1298,7 @@ Defina nombres de perfiles distintos. failed: - failed: + error: @@ -2699,7 +2699,7 @@ El valor predeterminado es publicar una aplicación dependiente del marco. retried - retried + volver a intentarlo @@ -2983,7 +2983,7 @@ Su proyecto tiene como destino varias plataformas. Especifique la que quiere usa skipped: - skipped: + omitido: @@ -3123,7 +3123,7 @@ Su proyecto tiene como destino varias plataformas. Especifique la que quiere usa succeeded: - succeeded: + correcto: @@ -3589,7 +3589,7 @@ y los identificadores de los paquetes correspondientes a las herramientas instal total: - total: + total: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index 3b1487a7704..710630a9a7f 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -1164,12 +1164,12 @@ Pour découvrir plus d’informations, consultez https://aka.ms/dotnet-test/mtp. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + Commande de test .NET pour Microsoft.Testing.Platform (activée via le fichier « global.json »). Cela prend uniquement en charge Microsoft.Testing.Platform et ne prend pas en charge VSTest. Pour plus d'informations, consultez https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + Commande de test .NET pour VSTest. Pour utiliser Microsoft.Testing.Platform, optez pour la commande basée sur Microsoft.Testing.Platform via global.json. Pour plus d'informations, consultez https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Faites en sorte que les noms de profil soient distincts. duration: - duration: + durée : error: - error: + erreur : @@ -1298,7 +1298,7 @@ Faites en sorte que les noms de profil soient distincts. failed: - failed: + échec : @@ -2699,7 +2699,7 @@ La valeur par défaut est de publier une application dépendante du framework. retried - retried + réessayé @@ -2983,7 +2983,7 @@ Votre projet cible plusieurs frameworks. Spécifiez le framework à exécuter à skipped: - skipped: + ignoré : @@ -3123,7 +3123,7 @@ Votre projet cible plusieurs frameworks. Spécifiez le framework à exécuter à succeeded: - succeeded: + réussie : @@ -3589,7 +3589,7 @@ et les ID de package correspondants aux outils installés, utilisez la commande total: - total: + total : diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index fffbb67c75e..69b69e64182 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -1164,12 +1164,12 @@ Per altre informazioni, vedere https://aka.ms/dotnet-test/mtp. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + Comando di test .NET per Microsoft.Testing.Platform (attivato tramite il file 'global.json'). Supporta solo Microsoft.Testing.Platform e non VSTest. Per altre informazioni, vedere https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + Comando di test .NET per VSTest. Per usare Microsoft.Testing.Platform, attivare il comando basato su Microsoft.Testing.Platform tramite global.json. Per altre informazioni, vedere https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Rendi distinti i nomi profilo. duration: - duration: + durata: error: - error: + errore: @@ -1298,7 +1298,7 @@ Rendi distinti i nomi profilo. failed: - failed: + non riuscito: @@ -2699,7 +2699,7 @@ Per impostazione predefinita, viene generato un pacchetto dipendente dal framewo retried - retried + ripetuto @@ -2983,7 +2983,7 @@ Il progetto è destinato a più framework. Specificare il framework da eseguire skipped: - skipped: + ignorato: @@ -3123,7 +3123,7 @@ Il progetto è destinato a più framework. Specificare il framework da eseguire succeeded: - succeeded: + operazione completata: @@ -3589,7 +3589,7 @@ e gli ID pacchetto corrispondenti per gli strumenti installati usando il comando total: - total: + totale: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index 4a9b4564cd8..4a83f985e87 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -1164,12 +1164,12 @@ See https://aka.ms/dotnet-test/mtp for more information. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + Microsoft.Testing.Platform 用の .NET テスト コマンド ('global.json' ファイルでオプトイン済み)。これは Microsoft.Testing.Platform のみをサポートしており、VSTest には対応していません。詳細については、https://aka.ms/dotnet-test をご覧ください。 {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + VSTest 用の .NET テスト コマンド。Microsoft.Testing.Platform を使用するには、global.json ファイルで Microsoft.Testing.Platform ベースのコマンドにオプトインしてください。詳細については、https://aka.ms/dotnet-test をご覧ください。 {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Make the profile names distinct. duration: - duration: + 期間: error: - error: + エラー: @@ -1298,7 +1298,7 @@ Make the profile names distinct. failed: - failed: + 失敗: @@ -2699,7 +2699,7 @@ The default is to publish a framework-dependent application. retried - retried + 再試行済み @@ -2983,7 +2983,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' skipped: - skipped: + スキップ済み: @@ -3123,7 +3123,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' succeeded: - succeeded: + 成功: @@ -3589,7 +3589,7 @@ and the corresponding package Ids for installed tools using the command total: - total: + 合計: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index d7a462877fb..f96a7af1b6f 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -1164,12 +1164,12 @@ See https://aka.ms/dotnet-test/mtp for more information. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + Microsoft.Testing.Platform용 .NET 테스트 명령입니다('global.json' 파일을 통해 옵트인). 이는 Microsoft.Testing.Platform만 지원하며 VSTest를 지원하지 않습니다. 자세한 내용은 https://aka.ms/dotnet-test를 참조하세요. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + VSTest에 대한 .NET 테스트 명령입니다. Microsoft.Testing.Platform을 사용하려면 global.json을 통해 Microsoft.Testing.Platform 기반 명령을 옵트인합니다. 자세한 내용은 https://aka.ms/dotnet-test를 참조하세요. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Make the profile names distinct. duration: - duration: + 기간: error: - error: + 오류: @@ -1298,7 +1298,7 @@ Make the profile names distinct. failed: - failed: + 실패: @@ -2699,7 +2699,7 @@ The default is to publish a framework-dependent application. retried - retried + 다시 시도됨 @@ -2983,7 +2983,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' skipped: - skipped: + 건너뜀: @@ -3123,7 +3123,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' succeeded: - succeeded: + 성공: @@ -3589,7 +3589,7 @@ and the corresponding package Ids for installed tools using the command total: - total: + 합계: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index 455c06c0f7d..e88469c1efc 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -1164,12 +1164,12 @@ Aby uzyskać więcej informacji, zobacz https://aka.ms/dotnet-test/mtp. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + Polecenie testowe platformy .NET dla elementu Microsoft.Testing.Platform (aktywowane przez plik „global.json”). Obsługuje tylko Microsoft.Testing.Platform i nie obsługuje VSTest. Aby uzyskać więcej informacji, zobacz https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + Polecenie testowe platformy .NET dla narzędzia VSTest. Aby korzystać z platformy Microsoft.Testing.Platform, wyraź zgodę na użycie polecenia opartego na Microsoft.Testing.Platform za pośrednictwem pliku global.json. Aby uzyskać więcej informacji, zobacz https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Rozróżnij nazwy profilów. duration: - duration: + czas trwania: error: - error: + błąd: @@ -1298,7 +1298,7 @@ Rozróżnij nazwy profilów. failed: - failed: + zakończone niepowodzeniem: @@ -2699,7 +2699,7 @@ Domyślnie publikowana jest aplikacja zależna od struktury. retried - retried + próbowano ponownie @@ -2983,7 +2983,7 @@ Projekt ma wiele platform docelowych. Określ platformę do uruchomienia przy u skipped: - skipped: + pominięto: @@ -3123,7 +3123,7 @@ Projekt ma wiele platform docelowych. Określ platformę do uruchomienia przy u succeeded: - succeeded: + zakończone powodzeniem: @@ -3589,7 +3589,7 @@ i odpowiednie identyfikatory pakietów zainstalowanych narzędzi można znaleź total: - total: + suma: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index f999a934e37..52b11f5c695 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -1164,12 +1164,12 @@ Consulte https://aka.ms/dotnet-test/mtp para obter mais informações. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + Comando de Teste .NET para Microsoft.Testing.Platform (aceito por meio do arquivo 'global.json'). Isso dá suporte apenas a Microsoft.Testing.Platform e não dá suporte a VSTest. Para obter mais informações, confira https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + Comando de Teste .NET para VSTest. Para usar a Microsoft.Testing.Platform, faça a aceitação do comando baseado em Microsoft.Testing.Platform por meio do global.json. Para obter mais informações, confira https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Diferencie os nomes dos perfis. duration: - duration: + duração: error: - error: + erro: @@ -1298,7 +1298,7 @@ Diferencie os nomes dos perfis. failed: - failed: + falhou: @@ -2699,7 +2699,7 @@ O padrão é publicar uma aplicação dependente de framework. retried - retried + repetido @@ -2983,7 +2983,7 @@ Ele tem diversas estruturas como destino. Especifique que estrutura executar usa skipped: - skipped: + ignorados: @@ -3123,7 +3123,7 @@ Ele tem diversas estruturas como destino. Especifique que estrutura executar usa succeeded: - succeeded: + concluído com êxito: @@ -3589,7 +3589,7 @@ e as Ids de pacote correspondentes para as ferramentas instaladas usando o coman total: - total: + total: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index adae2e4b3b1..bab1f4575a7 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -1164,12 +1164,12 @@ See https://aka.ms/dotnet-test/mtp for more information. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + Тестовая команда .NET для Microsoft.Testing.Platform (предоставлено согласие с помощью файла global.json). Поддерживается только Microsoft.Testing.Platform, VSTest не поддерживается. Дополнительные сведения см. на странице https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + Тестовая команда .NET для VSTest. Чтобы использовать Microsoft.Testing.Platform, согласитесь на использование команды на основе Microsoft.Testing.Platform посредством global.json. Дополнительные сведения см. на странице https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Make the profile names distinct. duration: - duration: + длительность: error: - error: + ошибка: @@ -1298,7 +1298,7 @@ Make the profile names distinct. failed: - failed: + сбой: @@ -2699,7 +2699,7 @@ The default is to publish a framework-dependent application. retried - retried + повторено @@ -2983,7 +2983,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' skipped: - skipped: + пропущено: @@ -3123,7 +3123,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' succeeded: - succeeded: + успешно: @@ -3590,7 +3590,7 @@ and the corresponding package Ids for installed tools using the command total: - total: + итог: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index 4e19bf47de4..1f1f787d8af 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -1164,12 +1164,12 @@ Daha fazla bilgi için https://aka.ms/dotnet-test/mtp adresine bakın. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + Microsoft.Testing.Platform için .NET Test Komutu ('global.json' dosyasıyla seçildi). Bu sadece Microsoft.Testing.Platform'u destekler, VSTest'i desteklemez. Daha fazla bilgi için bkz. https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + VSTest için .NET Test Komutu. Microsoft.Testing.Platform'u kullanmak için global.json üzerinden Microsoft.Testing.Platform tabanlı komutu seçin. Daha fazla bilgi için bkz. https://aka.ms/dotnet-test. {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Lütfen profil adlarını değiştirin. duration: - duration: + süre: error: - error: + hata: @@ -1298,7 +1298,7 @@ Lütfen profil adlarını değiştirin. failed: - failed: + başarısız oldu: @@ -2699,7 +2699,7 @@ Varsayılan durum, çerçeveye bağımlı bir uygulama yayımlamaktır. retried - retried + yeniden denendi @@ -2983,7 +2983,7 @@ Projeniz birden fazla Framework'ü hedefliyor. '{0}' kullanarak hangi Framework' skipped: - skipped: + atlandı: @@ -3123,7 +3123,7 @@ Projeniz birden fazla Framework'ü hedefliyor. '{0}' kullanarak hangi Framework' succeeded: - succeeded: + başarılı: @@ -3589,7 +3589,7 @@ karşılık gelen paket kimliklerini bulmak için total: - total: + toplam: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index 85e43f3d508..bf50f4c94c5 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -1164,12 +1164,12 @@ See https://aka.ms/dotnet-test/mtp for more information. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + 适用于 Microsoft.Testing.Platform 的 .NET 测试命令(已通过 "global.json" 文件选择加入)。此命令仅支持 Microsoft.Testing.Platform,不支持 VSTest。有关详细信息,请参阅 https://aka.ms/dotnet-test。 {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + 适用于 VSTest 的 .NET 测试命令。若要使用 Microsoft.Testing.Platform,请通过 global.json 选择加入基于 Microsoft.Testing.Platform 的命令。有关详细信息,请参阅 https://aka.ms/dotnet-test。 {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Make the profile names distinct. duration: - duration: + 持续时间: error: - error: + 错误: @@ -1298,7 +1298,7 @@ Make the profile names distinct. failed: - failed: + 失败: @@ -2699,7 +2699,7 @@ The default is to publish a framework-dependent application. retried - retried + 已重试 @@ -2983,7 +2983,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' skipped: - skipped: + 已跳过: @@ -3123,7 +3123,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' succeeded: - succeeded: + 成功: @@ -3589,7 +3589,7 @@ and the corresponding package Ids for installed tools using the command total: - total: + 总计: diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index 7023d8771c0..31bed5db183 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -1164,12 +1164,12 @@ See https://aka.ms/dotnet-test/mtp for more information. .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for Microsoft.Testing.Platform (opted-in via 'global.json' file). This only supports Microsoft.Testing.Platform and doesn't support VSTest. For more information, see https://aka.ms/dotnet-test. + .NET 測試命令,適用於 Microsoft.Testing.Platform (透過 'global.json' 檔案選擇加入)。此命令僅支援 Microsoft.Testing.Platform,不支援 VSTest。如需詳細資訊,請參閱 https://aka.ms/dotnet-test。 {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. - .NET Test Command for VSTest. To use Microsoft.Testing.Platform, opt-in to the Microsoft.Testing.Platform-based command via global.json. For more information, see https://aka.ms/dotnet-test. + 適用於 VSTest 的 .NET 測試命令。若要使用 Microsoft.Testing.Platform,請透過 global.json 選擇加入以 Microsoft.Testing.Platform 為基礎的命令。如需詳細資訊,請參閱 https://aka.ms/dotnet-test。 {Locked="global.json"}{Locked="Microsoft.Testing.Platform"}{Locked="VSTest"} @@ -1238,12 +1238,12 @@ Make the profile names distinct. duration: - duration: + 期間: error: - error: + 錯誤: @@ -1298,7 +1298,7 @@ Make the profile names distinct. failed: - failed: + 失敗: @@ -2699,7 +2699,7 @@ The default is to publish a framework-dependent application. retried - retried + 已重試 @@ -2983,7 +2983,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' skipped: - skipped: + 已略過: @@ -3123,7 +3123,7 @@ Your project targets multiple frameworks. Specify which framework to run using ' succeeded: - succeeded: + 已成功: @@ -3589,7 +3589,7 @@ and the corresponding package Ids for installed tools using the command total: - total: + 總計: diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.cs.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.cs.xlf index 793563fbddd..a55342a500c 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.cs.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.cs.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Odkaz na balíček ve formě identifikátoru balíčku, jako je „{0}“, nebo identifikátor balíčku a verze oddělené znakem @, například „{0}@{1}“. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.de.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.de.xlf index 75a8ea0992b..92adccab483 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.de.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.de.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Paketverweis in Form eines Paketbezeichners wie {0} oder Paketbezeichner und -version getrennt durch „@“ wie „{0}@{1}“. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.es.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.es.xlf index e1598973152..db4dd74c144 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.es.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.es.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Referencia de paquete en forma de identificador de paquete como "{0}" o identificador de paquete y versión separados por "@", como "{0}@{1}". diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.fr.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.fr.xlf index c559d991fdb..f9b5582e430 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.fr.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.fr.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Référence de package sous la forme d’un identificateur de package tel que « {0} » ou d’un identificateur de package et d’une version séparés par « @ », comme « {0}@{1} ». diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.it.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.it.xlf index 632432b2b28..8e5fb8a55e0 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.it.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.it.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Riferimento al pacchetto sotto forma di identificatore di pacchetto, ad esempio '{0}', oppure identificatore e versione di pacchetto separati da '@', ad esempio '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ja.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ja.xlf index 4ec60d0c7ee..2504e04d917 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ja.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ja.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + '{0}' のようなパッケージ ID の形式のパッケージ参照、または '{0}@{1}' のように '@' で区切られたパッケージ ID とバージョンです。 diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ko.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ko.xlf index c65066c2341..af4f6dc21b6 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ko.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ko.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + '{0}'과 같은 패키지 식별자 또는 '{0}@{1}'과 같이 '@'로 구분된 패키지 식별자 및 버전 형식의 패키지 참조입니다. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.pl.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.pl.xlf index 47183ec7a67..b92f633f89d 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.pl.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.pl.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Odwołanie do pakietu w formie identyfikatora pakietu, takiego jak „{0}” lub identyfikatora pakietu i wersji, rozdzielonych znakiem „@”, np. „{0}@{1}”. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf index fccf80013c6..48cd96b70fa 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Referência de pacote na forma de um identificador de pacote como '{0}' ou identificador de pacote e versão separados por '@', como '{0}@{1}'. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ru.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ru.xlf index 3814f20f1ca..774a83ee7bd 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.ru.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.ru.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + Ссылка на пакет в виде идентификатора пакета, например "{0}", или идентификатора пакета и версии, разделенных "@", например "{0}@{1}". diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.tr.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.tr.xlf index e6dc0a5df79..e3a3c95596e 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.tr.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.tr.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + '{0}' gibi bir paket tanımlayıcısı veya '{0}@{1}' gibi '@' ile ayrılmış paket tanımlayıcısı ve sürümü şeklinde paket başvurusu. diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf index 7dc1e93e52e..12a34a5c5fa 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + 包引用的格式为包标识符,如 ‘{0}’,或由 ‘@’ 分隔的包标识符和版本,如 ‘{0}@{1}’。 diff --git a/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf b/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf index bd3384fb806..7666715348c 100644 --- a/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf +++ b/src/sdk/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf @@ -784,7 +784,7 @@ setx PATH "%PATH%;{0}" Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. - Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'. + 套件參考的格式為套件識別碼,例如 '{0}',或是以 '@' 分隔的套件識別碼和版本,例如 '{0}@{1}'。 diff --git a/src/sdk/src/Layout/pkg/windows/bundles/sdk/bundle.wxs b/src/sdk/src/Layout/pkg/windows/bundles/sdk/bundle.wxs index 5836502fcd6..2503b1dac02 100644 --- a/src/sdk/src/Layout/pkg/windows/bundles/sdk/bundle.wxs +++ b/src/sdk/src/Layout/pkg/windows/bundles/sdk/bundle.wxs @@ -27,7 +27,13 @@ - + + + + + + diff --git a/src/sdk/src/Layout/redist/dnx.ps1 b/src/sdk/src/Layout/redist/dnx.ps1 deleted file mode 100644 index ff880f85e2f..00000000000 --- a/src/sdk/src/Layout/redist/dnx.ps1 +++ /dev/null @@ -1,8 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -# PowerShell script to launch dotnet.exe with 'dnx' and all passed arguments -$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition -$dotnet = Join-Path $scriptDir 'dotnet.exe' -& $dotnet dnx @Args -exit $LASTEXITCODE diff --git a/src/sdk/src/Layout/redist/targets/GenerateInstallerLayout.targets b/src/sdk/src/Layout/redist/targets/GenerateInstallerLayout.targets index 4c7aa7749e3..069c6a2fde2 100644 --- a/src/sdk/src/Layout/redist/targets/GenerateInstallerLayout.targets +++ b/src/sdk/src/Layout/redist/targets/GenerateInstallerLayout.targets @@ -67,7 +67,6 @@ - diff --git a/src/sdk/src/Layout/redist/targets/GeneratePackagePruneData.targets b/src/sdk/src/Layout/redist/targets/GeneratePackagePruneData.targets index 157eeabd5cd..f414f6582c7 100644 --- a/src/sdk/src/Layout/redist/targets/GeneratePackagePruneData.targets +++ b/src/sdk/src/Layout/redist/targets/GeneratePackagePruneData.targets @@ -30,13 +30,12 @@ - - + - + DependsOnTargets="GetTargetingPacksForPruneData"> + diff --git a/src/sdk/src/Layout/redist/targets/OverlaySdkOnLKG.targets b/src/sdk/src/Layout/redist/targets/OverlaySdkOnLKG.targets index 19505de69d5..faf995466d4 100644 --- a/src/sdk/src/Layout/redist/targets/OverlaySdkOnLKG.targets +++ b/src/sdk/src/Layout/redist/targets/OverlaySdkOnLKG.targets @@ -34,7 +34,7 @@ + UseHardLinksIfPossible="false" /> - diff --git a/src/sdk/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/EditorConfig/Dotnet/.editorconfig b/src/sdk/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/EditorConfig/Dotnet/.editorconfig index bb88786e7b5..af3d70051e2 100644 --- a/src/sdk/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/EditorConfig/Dotnet/.editorconfig +++ b/src/sdk/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/EditorConfig/Dotnet/.editorconfig @@ -9,7 +9,7 @@ indent_style = space indent_size = 2 # Xml project files -[*.{csproj,fsproj,vbproj,proj}] +[*.{csproj,fsproj,vbproj,proj,slnx}] indent_size = 2 # Xml config files diff --git a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/Company.TestProject1.csproj b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/Company.TestProject1.csproj index b4490a1d30f..415f0f4b220 100644 --- a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/Company.TestProject1.csproj +++ b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/Company.TestProject1.csproj @@ -1,5 +1,5 @@  - + net10.0 @@ -43,7 +43,7 @@ - + diff --git a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/Company.TestProject1.fsproj b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/Company.TestProject1.fsproj index a1b85e78555..6c64e1cd116 100644 --- a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/Company.TestProject1.fsproj +++ b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/Company.TestProject1.fsproj @@ -1,5 +1,5 @@ - + net10.0 @@ -48,7 +48,7 @@ - + diff --git a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj index b4490a1d30f..415f0f4b220 100644 --- a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj +++ b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj @@ -1,5 +1,5 @@  - + net10.0 @@ -43,7 +43,7 @@ - + diff --git a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj index 9c6ca5d3e25..2cffa453be0 100644 --- a/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj +++ b/src/sdk/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj @@ -1,5 +1,5 @@  - + net10.0 @@ -44,8 +44,8 @@ - - + + diff --git a/src/sdk/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/TestProject.csproj b/src/sdk/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/TestProject.csproj index ff9709d80d6..7bf348d2d58 100644 --- a/src/sdk/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/TestProject.csproj +++ b/src/sdk/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/TestProject.csproj @@ -1,13 +1,12 @@ - + $(CurrentTargetFramework) False - 17.12.6 - \ No newline at end of file + diff --git a/src/sdk/test/dotnet-new.IntegrationTests/Approvals/AllCommonItemsCreate.-o#EditorConfig-file#-n#item.verified/EditorConfig-file/.editorconfig b/src/sdk/test/dotnet-new.IntegrationTests/Approvals/AllCommonItemsCreate.-o#EditorConfig-file#-n#item.verified/EditorConfig-file/.editorconfig index 37f826f6640..fa2cc7622c2 100644 --- a/src/sdk/test/dotnet-new.IntegrationTests/Approvals/AllCommonItemsCreate.-o#EditorConfig-file#-n#item.verified/EditorConfig-file/.editorconfig +++ b/src/sdk/test/dotnet-new.IntegrationTests/Approvals/AllCommonItemsCreate.-o#EditorConfig-file#-n#item.verified/EditorConfig-file/.editorconfig @@ -9,7 +9,7 @@ indent_style = space indent_size = 2 # Xml project files -[*.{csproj,fsproj,vbproj,proj}] +[*.{csproj,fsproj,vbproj,proj,slnx}] indent_size = 2 # Xml config files diff --git a/src/sdk/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/src/sdk/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs index 104438d0808..501ce980b20 100644 --- a/src/sdk/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs +++ b/src/sdk/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs @@ -440,6 +440,64 @@ public async Task AutoRestartOnRudeEdit(bool nonInteractive) await App.WaitForOutputLineContaining(MessageDescriptor.HotReloadSucceeded); } + [Theory] + [CombinatorialData] + public async Task AutoRestartOnRuntimeRudeEdit(bool nonInteractive) + { + var testAsset = TestAssets.CopyTestAsset("WatchHotReloadApp") + .WithSource(); + + var tfm = ToolsetInfo.CurrentTargetFramework; + var programPath = Path.Combine(testAsset.Path, "Program.cs"); + + // Changes the type of lambda without updating top-level code. + // The loop will end up calling the old version of the lambda resulting in runtime rude edit. + + File.WriteAllText(programPath, """ + using System; + using System.Threading; + + var d = C.F(); + + while (true) + { + Thread.Sleep(250); + d(1); + } + + class C + { + public static Action F() + { + return a => + { + Console.WriteLine(a.GetType()); + }; + } + } + """); + + App.Start(testAsset, nonInteractive ? ["--non-interactive"] : []); + + await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); + await App.WaitUntilOutputContains("System.Int32"); + App.Process.ClearOutput(); + + UpdateSourceFile(programPath, src => src.Replace("Action", "Action")); + + await App.WaitForOutputLineContaining(MessageDescriptor.WaitingForChanges); + await App.WaitUntilOutputContains("System.Byte"); + + App.AssertOutputContains($"dotnet watch 🕵️ [WatchHotReloadApp ({tfm})] HotReloadException handler installed."); + App.AssertOutputContains($"dotnet watch 🕵️ [WatchHotReloadApp ({tfm})] Runtime rude edit detected:"); + + App.AssertOutputContains($"dotnet watch ⚠ [WatchHotReloadApp ({tfm})] " + + "Attempted to invoke a deleted lambda or local function implementation. " + + "This can happen when lambda or local function is deleted while the application is running."); + + App.AssertOutputContains(MessageDescriptor.RestartingApplication, $"WatchHotReloadApp ({tfm})"); + } + [Fact] public async Task AutoRestartOnRudeEditAfterRestartPrompt() { diff --git a/src/sdk/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs b/src/sdk/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs index 499c04e6883..ff2c8491194 100644 --- a/src/sdk/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs +++ b/src/sdk/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs @@ -526,7 +526,7 @@ public async Task RudeEditInProjectWithoutRunningProcess() // Terminate the process: Log($"Terminating process {runningProject.ProjectNode.GetDisplayName()} ..."); - await runningProject.TerminateAsync(isRestarting: false); + await runningProject.TerminateAsync(); // rude edit in A (changing assembly level attribute): UpdateSourceFile(serviceSourceA2, """ diff --git a/src/sdk/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs b/src/sdk/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs index aeaffc43f28..c80299e56b7 100644 --- a/src/sdk/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs +++ b/src/sdk/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs @@ -249,9 +249,8 @@ private static void AssertSubstringPresence(string expected, IEnumerable var message = new StringBuilder(); - message.AppendLine(expectedPresent - ? "Expected text found in the output:" + ? "Expected text not found in the output:" : "Text not expected to be found in the output:"); message.AppendLine(expected); diff --git a/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs b/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs index eb5678178da..12a75b9493e 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs @@ -214,101 +214,5 @@ public void ItIgnoresNonIntegerPropertiesDuringAggregation() fakeTelemetry.LogEntry.Properties.Should().NotContainKey("InvalidProperty"); fakeTelemetry.LogEntry.Properties.Should().NotContainKey("InvalidProperty2"); } - - [Fact] - public void ItAggregatesEvents() - { - var fakeTelemetry = new FakeTelemetry(); - fakeTelemetry.Enabled = true; - var logger = new MSBuildLogger(fakeTelemetry); - - var event1 = new TelemetryEventArgs - { - EventName = MSBuildLogger.TaskFactoryTelemetryAggregatedEventName, - Properties = new Dictionary - { - { "AssemblyTaskFactoryTasksExecutedCount", "2" }, - { "RoslynCodeTaskFactoryTasksExecutedCount", "1" } - } - }; - - var event2 = new TelemetryEventArgs - { - EventName = MSBuildLogger.TaskFactoryTelemetryAggregatedEventName, - Properties = new Dictionary - { - { "AssemblyTaskFactoryTasksExecutedCount", "3" }, - { "CustomTaskFactoryTasksExecutedCount", "2" } - } - }; - - var event3 = new TelemetryEventArgs - { - EventName = MSBuildLogger.TasksTelemetryAggregatedEventName, - Properties = new Dictionary - { - { "TasksExecutedCount", "3" }, - { "TaskHostTasksExecutedCount", "2" } - } - }; - - var event4 = new TelemetryEventArgs - { - EventName = MSBuildLogger.TasksTelemetryAggregatedEventName, - Properties = new Dictionary - { - { "TasksExecutedCount", "5" } - } - }; - - logger.AggregateEvent(event1); - logger.AggregateEvent(event2); - logger.AggregateEvent(event3); - logger.AggregateEvent(event4); - - logger.SendAggregatedEventsOnBuildFinished(fakeTelemetry); - - fakeTelemetry.LogEntries.Should().HaveCount(2); - - var taskFactoryEntry = fakeTelemetry.LogEntries.FirstOrDefault(e => e.EventName == $"msbuild/{MSBuildLogger.TaskFactoryTelemetryAggregatedEventName}"); - taskFactoryEntry.Should().NotBeNull(); - taskFactoryEntry.Properties["AssemblyTaskFactoryTasksExecutedCount"].Should().Be("5"); // 2 + 3 - taskFactoryEntry.Properties["RoslynCodeTaskFactoryTasksExecutedCount"].Should().Be("1"); // 1 + 0 - taskFactoryEntry.Properties["CustomTaskFactoryTasksExecutedCount"].Should().Be("2"); // 0 + 2 - - var tasksEntry = fakeTelemetry.LogEntries.FirstOrDefault(e => e.EventName == $"msbuild/{MSBuildLogger.TasksTelemetryAggregatedEventName}"); - tasksEntry.Should().NotBeNull(); - tasksEntry.Properties["TasksExecutedCount"].Should().Be("8"); // 3 + 5 - tasksEntry.Properties["TaskHostTasksExecutedCount"].Should().Be("2"); // 2 + 0 - } - - [Fact] - public void ItIgnoresNonIntegerPropertiesDuringAggregation() - { - var fakeTelemetry = new FakeTelemetry(); - fakeTelemetry.Enabled = true; - var logger = new MSBuildLogger(fakeTelemetry); - - var eventArgs = new TelemetryEventArgs - { - EventName = MSBuildLogger.TaskFactoryTelemetryAggregatedEventName, - Properties = new Dictionary - { - { "AssemblyTaskFactoryTasksExecutedCount", "3" }, - { "InvalidProperty", "not-a-number" }, - { "InvalidProperty2", "1.234" }, - } - }; - - logger.AggregateEvent(eventArgs); - - logger.SendAggregatedEventsOnBuildFinished(fakeTelemetry); - - fakeTelemetry.LogEntry.Should().NotBeNull(); - fakeTelemetry.LogEntry.EventName.Should().Be($"msbuild/{MSBuildLogger.TaskFactoryTelemetryAggregatedEventName}"); - fakeTelemetry.LogEntry.Properties["AssemblyTaskFactoryTasksExecutedCount"].Should().Be("3"); - fakeTelemetry.LogEntry.Properties.Should().NotContainKey("InvalidProperty"); - fakeTelemetry.LogEntry.Properties.Should().NotContainKey("InvalidProperty2"); - } } } diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs b/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs index 90763462aeb..72a600549d6 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs @@ -1154,6 +1154,50 @@ public void Directives_EmptyName( expectedWildcardPattern: RunFileTests.DirectiveError("/app/Program.cs", 1, CliCommandStrings.MissingDirectiveName, directive)); } + [Theory] + [InlineData("")] + [InlineData(" ")] + public void Directives_EmptyValue(string value) + { + VerifyConversion( + inputCSharp: $""" + #:property TargetFramework={value} + #:property Prop1={value} + #:sdk First@{value} + #:sdk Second@{value} + #:package P1@{value} + """, + expectedProject: """ + + + + + + Exe + enable + enable + true + true + + + + + + + + + + + """, + expectedCSharp: ""); + + VerifyConversionThrows( + inputCSharp: $""" + #:project{value} + """, + expectedWildcardPattern: RunFileTests.DirectiveError("/app/Program.cs", 1, CliCommandStrings.MissingDirectiveName, "project")); + } + [Fact] public void Directives_MissingPropertyValue() { diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs b/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs index 541788369fb..54c5c845493 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs @@ -1613,6 +1613,230 @@ public void NoBuild_02() .And.HaveStdOut("Changed"); } + [Fact] + public void Build_Library() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + var programFile = Path.Join(testInstance.Path, "lib.cs"); + File.WriteAllText(programFile, """ + #:property OutputType=Library + class C; + """); + + var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programFile); + if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true); + + new DotnetCommand(Log, "build", "lib.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run", "lib.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Fail() + .And.HaveStdErr(string.Format(CliCommandStrings.RunCommandExceptionUnableToRun, + Path.ChangeExtension(programFile, ".csproj"), + ToolsetInfo.CurrentTargetFrameworkVersion, + "Library")); + } + + [Fact] + public void Build_Library_MultiTarget() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + var programFile = Path.Join(testInstance.Path, "lib.cs"); + File.WriteAllText(programFile, $""" + #:property OutputType=Library + #:property PublishAot=false + #:property LangVersion=preview + #:property TargetFrameworks=netstandard2.0;{ToolsetInfo.CurrentTargetFramework} + class C; + """); + + // https://github.com/dotnet/sdk/issues/51077: cannot set this via `#:property` directive. + File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ + + + + + + """); + + var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programFile); + if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true); + + new DotnetCommand(Log, "build", "lib.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run", "lib.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Fail() + .And.HaveStdErr(string.Format(CliCommandStrings.RunCommandExceptionUnableToRunSpecifyFramework, "--framework")); + + new DotnetCommand(Log, "run", "lib.cs", "--framework", ToolsetInfo.CurrentTargetFramework) + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Fail() + .And.HaveStdErr(string.Format(CliCommandStrings.RunCommandExceptionUnableToRun, + Path.ChangeExtension(programFile, ".csproj"), + ToolsetInfo.CurrentTargetFrameworkVersion, + "Library")); + } + + [Fact] + public void Build_Module() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + var programFile = Path.Join(testInstance.Path, "module.cs"); + File.WriteAllText(programFile, """ + #:property OutputType=Module + #:property ProduceReferenceAssembly=false + class C; + """); + + var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programFile); + if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true); + + new DotnetCommand(Log, "build", "module.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run", "module.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Fail() + .And.HaveStdErr(string.Format(CliCommandStrings.RunCommandExceptionUnableToRun, + Path.ChangeExtension(programFile, ".csproj"), + ToolsetInfo.CurrentTargetFrameworkVersion, + "Module")); + } + + [Fact] + public void Build_WinExe() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + var programFile = Path.Join(testInstance.Path, "winexe.cs"); + File.WriteAllText(programFile, """ + #:property OutputType=WinExe + Console.WriteLine("Hello WinExe"); + """); + + var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programFile); + if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true); + + new DotnetCommand(Log, "build", "winexe.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run", "winexe.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass() + .And.HaveStdOut("Hello WinExe"); + } + + [Fact] + public void Build_Exe() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + var programFile = Path.Join(testInstance.Path, "exe.cs"); + File.WriteAllText(programFile, """ + #:property OutputType=Exe + Console.WriteLine("Hello Exe"); + """); + + var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programFile); + if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true); + + new DotnetCommand(Log, "build", "exe.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run", "exe.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass() + .And.HaveStdOut("Hello Exe"); + } + + [Fact] + public void Build_Exe_MultiTarget() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + var programFile = Path.Join(testInstance.Path, "exe.cs"); + File.WriteAllText(programFile, $""" + #:property OutputType=Exe + #:property PublishAot=false + #:property LangVersion=preview + #:property TargetFrameworks=netstandard2.0;{ToolsetInfo.CurrentTargetFramework} + Console.WriteLine("Hello Exe"); + """); + + // https://github.com/dotnet/sdk/issues/51077: cannot set this via `#:property` directive. + File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ + + + + + + """); + + var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programFile); + if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true); + + new DotnetCommand(Log, "build", "exe.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run", "exe.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Fail() + .And.HaveStdErr(string.Format(CliCommandStrings.RunCommandExceptionUnableToRunSpecifyFramework, "--framework")); + + new DotnetCommand(Log, "run", "exe.cs", "--framework", ToolsetInfo.CurrentTargetFramework) + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass() + .And.HaveStdOut("Hello Exe"); + } + + [Fact] + public void Build_AppContainerExe() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + var programFile = Path.Join(testInstance.Path, "appcontainerexe.cs"); + File.WriteAllText(programFile, """ + #:property OutputType=AppContainerExe + Console.WriteLine("Hello AppContainerExe"); + """); + + var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programFile); + if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true); + + new DotnetCommand(Log, "build", "appcontainerexe.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run", "appcontainerexe.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Fail() + .And.HaveStdErr(string.Format(CliCommandStrings.RunCommandExceptionUnableToRun, + Path.ChangeExtension(programFile, ".csproj"), + ToolsetInfo.CurrentTargetFrameworkVersion, + "AppContainerExe")); + } + [Fact] public void Publish() { diff --git a/src/source-manifest.json b/src/source-manifest.json index 2196f91ffcc..d76ac9e60ef 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -91,10 +91,10 @@ "commitSha": "082359066ee0064039b9b1f1f025bdd0507d06de" }, { - "barId": 286006, + "barId": 286464, "path": "sdk", "remoteUri": "https://github.com/dotnet/sdk", - "commitSha": "cf932ba08b38f8a148536f5d0e9c98d56280cc24" + "commitSha": "100134337cdbc0edb7a9a477b30ecc61f49bc92e" }, { "barId": 282656, From 7b963854036de63969691297c8ebb60325814a78 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 15:54:16 +0000 Subject: [PATCH 20/28] [release/10.0.1xx] Skip SB tests requiring MS artifacts in lite builds (#2826) Co-authored-by: Matt Thalman --- eng/pipelines/templates/stages/source-build-stages.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eng/pipelines/templates/stages/source-build-stages.yml b/eng/pipelines/templates/stages/source-build-stages.yml index a149ecc9eef..83eae0a477a 100644 --- a/eng/pipelines/templates/stages/source-build-stages.yml +++ b/eng/pipelines/templates/stages/source-build-stages.yml @@ -121,6 +121,8 @@ stages: withPreviousSDK: false # 🚫 disableSigning: true # ✅ createSourceArtifacts: false # 🚫 + ${{ if in(parameters.scope, 'lite') }}: + extraProperties: /p:DotNetSkipTestsRequiringMicrosoftArtifacts=true - ${{ if containsValue(parameters.verifications, 'source-build-stage2') }}: @@ -136,6 +138,8 @@ stages: disableSigning: true # ✅ createSourceArtifacts: false # 🚫 reuseBuildArtifactsFrom: 'SB_{0}_Online_MsftSdk_x64' + ${{ if in(parameters.scope, 'lite') }}: + extraProperties: /p:DotNetSkipTestsRequiringMicrosoftArtifacts=true ### Additional legs for full build ### - ${{ if in(parameters.scope, 'full') }}: From 24ad0997d18fc8b7e502ff23b50e8f98b83d9ac0 Mon Sep 17 00:00:00 2001 From: Nikola Milosavljevic Date: Fri, 10 Oct 2025 09:20:40 -0700 Subject: [PATCH 21/28] [release/10.0.1xx] Add tests for verification of expected set of Linux packages (#2773) --- .../LinuxInstallerTests.cs | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/test/Microsoft.DotNet.Installer.Tests/LinuxInstallerTests.cs b/test/Microsoft.DotNet.Installer.Tests/LinuxInstallerTests.cs index 14a0a7bf685..8c3114394e8 100755 --- a/test/Microsoft.DotNet.Installer.Tests/LinuxInstallerTests.cs +++ b/test/Microsoft.DotNet.Installer.Tests/LinuxInstallerTests.cs @@ -81,6 +81,10 @@ public partial class LinuxInstallerTests : IDisposable [GeneratedRegex(@"\s*\([^)]*\)", RegexOptions.CultureInvariant)] private static partial Regex RemoveVersionConstraintRegex { get; } + // Remove version numbers from package names: "dotnet-runtime-10.0.0-rc.1.25480.112-x64.rpm" -> "dotnet-runtime-*-x64.rpm" + [GeneratedRegex(@"\d+\.\d+\.\d+(?:-(?:rc|rtm|preview)(?:\.\d+)*)?", RegexOptions.CultureInvariant)] + private static partial Regex RemoveVersionFromPackageNameRegex { get; } + private const string RuntimeDepsRepo = "mcr.microsoft.com/dotnet/runtime-deps"; private const string RuntimeDepsVersion = "10.0-preview"; private const string DotnetRuntimeDepsPrefix = "dotnet-runtime-deps-"; @@ -170,6 +174,18 @@ public async Task DebPackageMetadataTest(string repo, string tag) ValidatePackageMetadata($"{repo}:{tag}", PackageType.Deb); } + [ConditionalFact(typeof(LinuxInstallerTests), nameof(IncludeRpmTests))] + public void ValidateRpmPackageList() + { + ValidatePackageList(PackageType.Rpm); + } + + [ConditionalFact(typeof(LinuxInstallerTests), nameof(IncludeDebTests))] + public void ValidateDebPackageList() + { + ValidatePackageList(PackageType.Deb); + } + private async Task InitializeContextAsync(PackageType packageType, bool initializeSharedContext = true) { string packageArchitecture = @@ -712,4 +728,80 @@ private static List ParseDebControlDependencies(string contents) return results; } + + private void ValidatePackageList(PackageType packageType) + { + string extension = packageType == PackageType.Rpm ? "*.rpm" : "*.deb"; + List expectedPatterns = GetExpectedPackagePatterns(packageType).OrderBy(p => p).ToList(); + + // Find all packages of the specified type and normalize by removing version numbers + List normalizedActual = Directory.GetFiles(Config.AssetsDirectory, extension, SearchOption.AllDirectories) + .Select(path => RemoveVersionFromPackageNameRegex.Replace(Path.GetFileName(path), "*")) + .Distinct() + .OrderBy(name => name) + .ToList(); + + Assert.True( + expectedPatterns.SequenceEqual(normalizedActual), + $"Package list validation failed for {packageType}:\nExpected:\n{string.Join("\n", expectedPatterns)}\nActual:\n{string.Join("\n", normalizedActual)}" + ); + } + + private List GetExpectedPackagePatterns(PackageType packageType) + { + string extension = packageType == PackageType.Rpm ? ".rpm" : ".deb"; + string arch = Config.Architecture == Architecture.X64 ? "x64" : + (packageType == PackageType.Rpm ? "aarch64" : "arm64"); + + var patterns = new List(); + + // Base package prefixes (common to both RPM and DEB) + var basePackages = new List + { + "aspnetcore-runtime", "aspnetcore-targeting-pack", "dotnet-apphost-pack", + "dotnet-host", "dotnet-hostfxr", "dotnet-runtime", "dotnet-sdk", "dotnet-targeting-pack" + }; + + // Add runtime-deps for DEB only (RPM only has distro-specific variants) + if (packageType == PackageType.Deb) + { + basePackages.Add("dotnet-runtime-deps"); + } + + // Standard variants + foreach (string package in basePackages) + { + patterns.Add($"{package}-*-{arch}{extension}"); + } + + // New key variants + foreach (string package in basePackages) + { + patterns.Add($"{package}-*-newkey-{arch}{extension}"); + } + + if (packageType == PackageType.Rpm) + { + // Azure Linux variants + foreach (string package in basePackages) + { + patterns.Add($"{package}-*-azl-{arch}{extension}"); + } + + // Runtime deps distro variants (RPM only) + string[] distros = new[] { "azl.3", "opensuse.15", "sles.15" }; + foreach (string distro in distros) + { + patterns.Add($"dotnet-runtime-deps-*-{distro}-{arch}{extension}"); + + // `azl` deps packages do not have a -newkey- variant + if (distro != "azl.3") + { + patterns.Add($"dotnet-runtime-deps-*-{distro}-newkey-{arch}{extension}"); + } + } + } + + return patterns; + } } From c50c747afd3865b10949f74db021755a588263e6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 12:00:42 -0700 Subject: [PATCH 22/28] [release/10.0.1xx] Source code updates from dotnet/runtime (#2830) Co-authored-by: dotnet-maestro[bot] --- .../pkg/sfx/installers/dotnet-host.proj | 7 +-- .../src/installer/pkg/sfx/installers/host.wxs | 45 +++---------------- .../ComputeWasmPublishAssets.cs | 21 +++++++-- src/source-manifest.json | 4 +- 4 files changed, 26 insertions(+), 51 deletions(-) diff --git a/src/runtime/src/installer/pkg/sfx/installers/dotnet-host.proj b/src/runtime/src/installer/pkg/sfx/installers/dotnet-host.proj index 64282f8de95..f834af089e1 100644 --- a/src/runtime/src/installer/pkg/sfx/installers/dotnet-host.proj +++ b/src/runtime/src/installer/pkg/sfx/installers/dotnet-host.proj @@ -13,10 +13,7 @@ Dotnet_CLI_SharedHost HostSrc - - afterInstallInitialize + afterInstallExecute false true sharedhost @@ -30,7 +27,7 @@ - + diff --git a/src/runtime/src/installer/pkg/sfx/installers/host.wxs b/src/runtime/src/installer/pkg/sfx/installers/host.wxs index fe074135150..2f53e3ba54c 100644 --- a/src/runtime/src/installer/pkg/sfx/installers/host.wxs +++ b/src/runtime/src/installer/pkg/sfx/installers/host.wxs @@ -39,20 +39,22 @@ - + + - + + @@ -60,6 +62,7 @@ + @@ -72,7 +75,6 @@ - @@ -86,43 +88,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/runtime/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs b/src/runtime/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs index c2332f2985d..98db78edc5f 100644 --- a/src/runtime/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs +++ b/src/runtime/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs @@ -420,6 +420,16 @@ private void ProcessSymbolAssets( } } + private string GetItemSpecWithoutFingerprint(ITaskItem asset) + => FingerprintAssets ? asset.GetMetadata("OriginalItemSpec") : asset.ItemSpec; + + private static string GetNonFingerprintedAssetItemSpec(ITaskItem asset) + { + var fileName = Path.GetFileName(asset.GetMetadata("OriginalItemSpec")); + var assetToUpdateItemSpec = Path.Combine(Path.GetDirectoryName(asset.ItemSpec), fileName); + return assetToUpdateItemSpec; + } + private void ComputeUpdatedAssemblies( IDictionary<(string, string assemblyName), ITaskItem> satelliteAssemblies, List filesToRemove, @@ -440,14 +450,15 @@ private void ComputeUpdatedAssemblies( foreach (var kvp in assemblyAssets) { var asset = kvp.Value; - var fileName = Path.GetFileName(asset.ItemSpec); + var fileName = Path.GetFileName(GetItemSpecWithoutFingerprint(asset)); + var assetToUpdateItemSpec = FingerprintAssets ? GetNonFingerprintedAssetItemSpec(asset) : asset.ItemSpec; if (IsWebCilEnabled) fileName = Path.ChangeExtension(fileName, ".dll"); if (resolvedAssembliesToPublish.TryGetValue(fileName, out var existing)) { // We found the assembly, so it'll have to be updated. - assetsToUpdate.Add(asset.ItemSpec, asset); + assetsToUpdate.Add(assetToUpdateItemSpec, asset); filesToRemove.Add(existing); if (!string.Equals(asset.ItemSpec, existing.GetMetadata("FullPath"), StringComparison.Ordinal)) { @@ -465,11 +476,12 @@ private void ComputeUpdatedAssemblies( { var satelliteAssembly = kvp.Value; var relatedAsset = satelliteAssembly.GetMetadata("RelatedAsset"); + if (assetsToUpdate.ContainsKey(relatedAsset)) { assetsToUpdate.Add(satelliteAssembly.ItemSpec, satelliteAssembly); var culture = satelliteAssembly.GetMetadata("AssetTraitValue"); - var fileName = Path.GetFileName(satelliteAssembly.ItemSpec); + var fileName = Path.GetFileName(GetItemSpecWithoutFingerprint(satelliteAssembly)); if (IsWebCilEnabled) fileName = Path.ChangeExtension(fileName, ".dll"); @@ -517,7 +529,8 @@ private void ComputeUpdatedAssemblies( ApplyPublishProperties(newAsemblyAsset); newAssets.Add(newAsemblyAsset); - updatedAssetsMap.Add(asset.ItemSpec, newAsemblyAsset); + var assetToUpdateItemSpec = FingerprintAssets ? GetNonFingerprintedAssetItemSpec(asset) : asset.ItemSpec; + updatedAssetsMap.Add(assetToUpdateItemSpec, newAsemblyAsset); break; default: // Satellite assembliess and compressed assets diff --git a/src/source-manifest.json b/src/source-manifest.json index d76ac9e60ef..753a181d819 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -79,10 +79,10 @@ "commitSha": "929ae2333a73eca047b9b6e2f01bf7121558308f" }, { - "barId": 286218, + "barId": 286526, "path": "runtime", "remoteUri": "https://github.com/dotnet/runtime", - "commitSha": "d321bc6abef02ed27790e8da3740d253976b9ac6" + "commitSha": "647691bc0fe3113ad72643efed1597676b525c55" }, { "barId": 277711, From a228ad4819d1763feb75c6f524552a2049a511d4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 19:34:14 +0000 Subject: [PATCH 23/28] [release/10.0.1xx] Source code updates from dotnet/aspnetcore (#2832) Co-authored-by: dotnet-maestro[bot] --- src/aspnetcore/eng/Version.Details.props | 184 ++++----- src/aspnetcore/eng/Version.Details.xml | 370 +++++++++--------- src/aspnetcore/global.json | 6 +- .../RazorComponentEndpointDataSource.cs | 40 +- ...RazorComponentEndpointDataSourceFactory.cs | 11 +- ...azorComponentsEndpointConventionBuilder.cs | 12 +- ...entsEndpointConventionBuilderExtensions.cs | 2 +- ...EndpointConventionBuilderExtensionsTest.cs | 4 +- .../Endpoints/test/HotReloadServiceTests.cs | 93 ++--- .../RazorComponentEndpointDataSourceTest.cs | 34 +- src/source-manifest.json | 4 +- 11 files changed, 369 insertions(+), 391 deletions(-) diff --git a/src/aspnetcore/eng/Version.Details.props b/src/aspnetcore/eng/Version.Details.props index ffe9c35f973..06e740a8cae 100644 --- a/src/aspnetcore/eng/Version.Details.props +++ b/src/aspnetcore/eng/Version.Details.props @@ -6,98 +6,98 @@ This file should be imported by eng/Versions.props - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-beta.25507.103 - 10.0.0-beta.25507.103 - 10.0.0-beta.25507.103 - 10.0.0-beta.25507.103 - 10.0.0-beta.25507.103 - 10.0.0-beta.25507.103 - 10.0.0-beta.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 3.2.0-preview.25507.103 - 7.0.0-rc.803 - 7.0.0-rc.803 - 7.0.0-rc.803 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 3.2.0-preview.25509.106 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 7.0.0-rc.1006 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 4.13.0-3.24613.7 4.13.0-3.24613.7 diff --git a/src/aspnetcore/eng/Version.Details.xml b/src/aspnetcore/eng/Version.Details.xml index 0f0a7ebe0bf..cc99cb2648b 100644 --- a/src/aspnetcore/eng/Version.Details.xml +++ b/src/aspnetcore/eng/Version.Details.xml @@ -8,333 +8,333 @@ See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md for instructions on using darc. --> - + - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac @@ -358,37 +358,37 @@ - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac https://github.com/dotnet/extensions @@ -440,17 +440,17 @@ https://github.com/dotnet/msbuild d1cce8d7cc03c23a4f1bad8e9240714fd9d199a3 - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac diff --git a/src/aspnetcore/global.json b/src/aspnetcore/global.json index c4cb92a9a95..abf6225284d 100644 --- a/src/aspnetcore/global.json +++ b/src/aspnetcore/global.json @@ -27,9 +27,9 @@ "jdk": "latest" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25507.103", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25507.103", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25507.103", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25509.106", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25509.106", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25509.106", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.WixToolset.Sdk": "5.0.2-dotnet.2737382" diff --git a/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentEndpointDataSource.cs b/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentEndpointDataSource.cs index a8161054279..7ce2a54419b 100644 --- a/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentEndpointDataSource.cs +++ b/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentEndpointDataSource.cs @@ -20,8 +20,8 @@ internal class RazorComponentEndpointDataSource<[DynamicallyAccessedMembers(Comp private readonly object _lock = new(); private readonly List> _conventions = []; private readonly List> _finallyConventions = []; + private readonly List> _componentApplicationBuilderActions = []; private readonly RazorComponentDataSourceOptions _options = new(); - private readonly ComponentApplicationBuilder _builder; private readonly IEndpointRouteBuilder _endpointRouteBuilder; private readonly ResourceCollectionResolver _resourceCollectionResolver; private readonly RenderModeEndpointProvider[] _renderModeEndpointProviders; @@ -32,33 +32,29 @@ internal class RazorComponentEndpointDataSource<[DynamicallyAccessedMembers(Comp private IChangeToken _changeToken; private IDisposable? _disposableChangeToken; // THREADING: protected by _lock - public Func SetDisposableChangeTokenAction = disposableChangeToken => disposableChangeToken; - // Internal for testing. - internal ComponentApplicationBuilder Builder => _builder; internal List> Conventions => _conventions; + internal List> ComponentApplicationBuilderActions => _componentApplicationBuilderActions; + internal CancellationTokenSource ChangeTokenSource => _cancellationTokenSource; public RazorComponentEndpointDataSource( - ComponentApplicationBuilder builder, IEnumerable renderModeEndpointProviders, IEndpointRouteBuilder endpointRouteBuilder, RazorComponentEndpointFactory factory, HotReloadService? hotReloadService = null) { - _builder = builder; _endpointRouteBuilder = endpointRouteBuilder; _resourceCollectionResolver = new ResourceCollectionResolver(endpointRouteBuilder); _renderModeEndpointProviders = renderModeEndpointProviders.ToArray(); _factory = factory; _hotReloadService = hotReloadService; - HotReloadService.ClearCacheEvent += OnHotReloadClearCache; DefaultBuilder = new RazorComponentsEndpointConventionBuilder( _lock, - builder, endpointRouteBuilder, _options, _conventions, - _finallyConventions); + _finallyConventions, + _componentApplicationBuilderActions); _cancellationTokenSource = new CancellationTokenSource(); _changeToken = new CancellationChangeToken(_cancellationTokenSource.Token); @@ -106,8 +102,20 @@ private void UpdateEndpoints() lock (_lock) { + _disposableChangeToken?.Dispose(); + _disposableChangeToken = null; + var endpoints = new List(); - var context = _builder.Build(); + + var componentApplicationBuilder = new ComponentApplicationBuilder(); + + foreach (var action in ComponentApplicationBuilderActions) + { + action?.Invoke(componentApplicationBuilder); + } + + var context = componentApplicationBuilder.Build(); + var configuredRenderModesMetadata = new ConfiguredRenderModesMetadata( [.. Options.ConfiguredRenderModes]); @@ -168,8 +176,7 @@ private void UpdateEndpoints() oldCancellationTokenSource?.Dispose(); if (_hotReloadService is { MetadataUpdateSupported: true }) { - _disposableChangeToken?.Dispose(); - _disposableChangeToken = SetDisposableChangeTokenAction(ChangeToken.OnChange(_hotReloadService.GetChangeToken, UpdateEndpoints)); + _disposableChangeToken = ChangeToken.OnChange(_hotReloadService.GetChangeToken, UpdateEndpoints); } } } @@ -195,15 +202,6 @@ private void AddBlazorWebEndpoints(List endpoints) } } - public void OnHotReloadClearCache(Type[]? types) - { - lock (_lock) - { - _disposableChangeToken?.Dispose(); - _disposableChangeToken = null; - } - } - public override IChangeToken GetChangeToken() { Initialize(); diff --git a/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentEndpointDataSourceFactory.cs b/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentEndpointDataSourceFactory.cs index 84327f3f6d5..a8f178a4fc2 100644 --- a/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentEndpointDataSourceFactory.cs +++ b/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentEndpointDataSourceFactory.cs @@ -17,9 +17,14 @@ internal class RazorComponentEndpointDataSourceFactory( { public RazorComponentEndpointDataSource CreateDataSource<[DynamicallyAccessedMembers(Component)] TRootComponent>(IEndpointRouteBuilder endpoints) { - var builder = ComponentApplicationBuilder.GetBuilder() ?? - DefaultRazorComponentApplication.Instance.GetBuilder(); + var dataSource = new RazorComponentEndpointDataSource(providers, endpoints, factory, hotReloadService); - return new RazorComponentEndpointDataSource(builder, providers, endpoints, factory, hotReloadService); + dataSource.ComponentApplicationBuilderActions.Add(builder => + { + var assembly = typeof(TRootComponent).Assembly; + IRazorComponentApplication.GetBuilderForAssembly(builder, assembly); + }); + + return dataSource; } } diff --git a/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilder.cs b/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilder.cs index 04b1daa9e95..46808fbfdfb 100644 --- a/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilder.cs +++ b/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilder.cs @@ -18,27 +18,25 @@ public sealed class RazorComponentsEndpointConventionBuilder : IEndpointConventi private readonly RazorComponentDataSourceOptions _options; private readonly List> _conventions; private readonly List> _finallyConventions; + private readonly List> _componentApplicationBuilderActions; internal RazorComponentsEndpointConventionBuilder( object @lock, - ComponentApplicationBuilder builder, IEndpointRouteBuilder endpointRouteBuilder, RazorComponentDataSourceOptions options, List> conventions, - List> finallyConventions) + List> finallyConventions, + List> componentApplicationBuilderActions) { _lock = @lock; - ApplicationBuilder = builder; EndpointRouteBuilder = endpointRouteBuilder; _options = options; _conventions = conventions; _finallyConventions = finallyConventions; + _componentApplicationBuilderActions = componentApplicationBuilderActions; } - /// - /// Gets the that is used to build the endpoints. - /// - internal ComponentApplicationBuilder ApplicationBuilder { get; } + internal List> ComponentApplicationBuilderActions => _componentApplicationBuilderActions; internal string? ManifestPath { get => _options.ManifestPath; set => _options.ManifestPath = value; } diff --git a/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilderExtensions.cs b/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilderExtensions.cs index fd0a6aec0c4..7cc4fa4dc76 100644 --- a/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilderExtensions.cs +++ b/src/aspnetcore/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilderExtensions.cs @@ -30,7 +30,7 @@ public static RazorComponentsEndpointConventionBuilder AddAdditionalAssemblies( foreach (var assembly in assemblies) { - builder.ApplicationBuilder.AddAssembly(assembly); + builder.ComponentApplicationBuilderActions.Add(b => b.AddAssembly(assembly)); } return builder; } diff --git a/src/aspnetcore/src/Components/Endpoints/test/Builder/RazorComponentsEndpointConventionBuilderExtensionsTest.cs b/src/aspnetcore/src/Components/Endpoints/test/Builder/RazorComponentsEndpointConventionBuilderExtensionsTest.cs index 70fa780fcba..e1a5116ee0b 100644 --- a/src/aspnetcore/src/Components/Endpoints/test/Builder/RazorComponentsEndpointConventionBuilderExtensionsTest.cs +++ b/src/aspnetcore/src/Components/Endpoints/test/Builder/RazorComponentsEndpointConventionBuilderExtensionsTest.cs @@ -245,7 +245,7 @@ public void MapRazorComponents_CanAddConventions_ToBlazorWebEndpoints(string fra private RazorComponentsEndpointConventionBuilder CreateRazorComponentsAppBuilder(IEndpointRouteBuilder endpointBuilder) { var builder = endpointBuilder.MapRazorComponents(); - builder.ApplicationBuilder.AddLibrary(new AssemblyComponentLibraryDescriptor( + builder.ComponentApplicationBuilderActions.Add(b => b.AddLibrary(new AssemblyComponentLibraryDescriptor( "App", [new PageComponentBuilder { PageType = typeof(App), @@ -253,7 +253,7 @@ [new PageComponentBuilder { AssemblyName = "App", }], [] - )); + ))); return builder; } diff --git a/src/aspnetcore/src/Components/Endpoints/test/HotReloadServiceTests.cs b/src/aspnetcore/src/Components/Endpoints/test/HotReloadServiceTests.cs index 011056c2e7c..a8e2280d77e 100644 --- a/src/aspnetcore/src/Components/Endpoints/test/HotReloadServiceTests.cs +++ b/src/aspnetcore/src/Components/Endpoints/test/HotReloadServiceTests.cs @@ -23,9 +23,8 @@ public class HotReloadServiceTests public void UpdatesEndpointsWhenHotReloadChangeTokenTriggered() { // Arrange - var builder = CreateBuilder(typeof(ServerComponent)); var services = CreateServices(typeof(MockEndpointProvider)); - var endpointDataSource = CreateDataSource(builder, services); + var endpointDataSource = CreateDataSource(services, ConfigureServerComponentBuilder); var invoked = false; // Act @@ -41,9 +40,8 @@ public void UpdatesEndpointsWhenHotReloadChangeTokenTriggered() public void AddNewEndpointWhenDataSourceChanges() { // Arrange - var builder = CreateBuilder(typeof(ServerComponent)); var services = CreateServices(typeof(MockEndpointProvider)); - var endpointDataSource = CreateDataSource(builder, services); + var endpointDataSource = CreateDataSource(services, ConfigureServerComponentBuilder); // Assert - 1 var endpoint = Assert.IsType( @@ -52,15 +50,17 @@ public void AddNewEndpointWhenDataSourceChanges() Assert.Equal("/server", endpoint.RoutePattern.RawText); // Act - 2 - endpointDataSource.Builder.Pages.AddFromLibraryInfo("TestAssembly2", new[] - { - new PageComponentBuilder + endpointDataSource.ComponentApplicationBuilderActions.Add( + b => b.Pages.AddFromLibraryInfo("TestAssembly2", new[] { - AssemblyName = "TestAssembly2", - PageType = typeof(StaticComponent), - RouteTemplates = new List { "/app/test" } - } - }); + new PageComponentBuilder + { + AssemblyName = "TestAssembly2", + PageType = typeof(StaticComponent), + RouteTemplates = new List { "/app/test" } + } + })); + HotReloadService.UpdateApplication(null); // Assert - 2 @@ -76,9 +76,8 @@ public void AddNewEndpointWhenDataSourceChanges() public void RemovesEndpointWhenDataSourceChanges() { // Arrange - var builder = CreateBuilder(typeof(ServerComponent)); var services = CreateServices(typeof(MockEndpointProvider)); - var endpointDataSource = CreateDataSource(builder, services); + var endpointDataSource = CreateDataSource(services, ConfigureServerComponentBuilder); // Assert - 1 var endpoint = Assert.IsType(Assert.Single(endpointDataSource.Endpoints, @@ -87,7 +86,7 @@ public void RemovesEndpointWhenDataSourceChanges() Assert.Equal("/server", endpoint.RoutePattern.RawText); // Act - 2 - endpointDataSource.Builder.RemoveLibrary("TestAssembly"); + endpointDataSource.ComponentApplicationBuilderActions.Add(b => b.RemoveLibrary("TestAssembly")); endpointDataSource.Options.ConfiguredRenderModes.Clear(); HotReloadService.UpdateApplication(null); @@ -100,9 +99,8 @@ public void RemovesEndpointWhenDataSourceChanges() public void ModifiesEndpointWhenDataSourceChanges() { // Arrange - var builder = CreateBuilder(typeof(ServerComponent)); var services = CreateServices(typeof(MockEndpointProvider)); - var endpointDataSource = CreateDataSource(builder, services); + var endpointDataSource = CreateDataSource(services, ConfigureServerComponentBuilder); // Assert - 1 var endpoint = Assert.IsType(Assert.Single(endpointDataSource.Endpoints, e => e.Metadata.GetMetadata() != null)); @@ -124,9 +122,8 @@ public void ModifiesEndpointWhenDataSourceChanges() public void NotifiesCompositeEndpointDataSource() { // Arrange - var builder = CreateBuilder(typeof(ServerComponent)); var services = CreateServices(typeof(MockEndpointProvider)); - var endpointDataSource = CreateDataSource(builder, services); + var endpointDataSource = CreateDataSource(services, ConfigureServerComponentBuilder); var compositeEndpointDataSource = new CompositeEndpointDataSource( new[] { endpointDataSource }); @@ -137,7 +134,7 @@ public void NotifiesCompositeEndpointDataSource() Assert.Equal("/server", compositeEndpoint.RoutePattern.RawText); // Act - 2 - endpointDataSource.Builder.Pages.RemoveFromAssembly("TestAssembly"); + endpointDataSource.ComponentApplicationBuilderActions.Add(b => b.Pages.RemoveFromAssembly("TestAssembly")); endpointDataSource.Options.ConfiguredRenderModes.Clear(); HotReloadService.UpdateApplication(null); @@ -148,37 +145,14 @@ public void NotifiesCompositeEndpointDataSource() Assert.Empty(compositePageEndpoints); } - private sealed class WrappedChangeTokenDisposable : IDisposable - { - public bool IsDisposed { get; private set; } - private readonly IDisposable _innerDisposable; - - public WrappedChangeTokenDisposable(IDisposable innerDisposable) - { - _innerDisposable = innerDisposable; - } - - public void Dispose() - { - IsDisposed = true; - _innerDisposable.Dispose(); - } - } - [Fact] public void ConfirmChangeTokenDisposedHotReload() { // Arrange - var builder = CreateBuilder(typeof(ServerComponent)); var services = CreateServices(typeof(MockEndpointProvider)); - var endpointDataSource = CreateDataSource(builder, services); - - WrappedChangeTokenDisposable wrappedChangeTokenDisposable = null; - - endpointDataSource.SetDisposableChangeTokenAction = (IDisposable disposableChangeToken) => { - wrappedChangeTokenDisposable = new WrappedChangeTokenDisposable(disposableChangeToken); - return wrappedChangeTokenDisposable; - }; + var endpointDataSource = CreateDataSource(services, ConfigureServerComponentBuilder, null); + var changeTokenSource = endpointDataSource.ChangeTokenSource; + var changeToken = endpointDataSource.GetChangeToken(); var endpoint = Assert.IsType(Assert.Single(endpointDataSource.Endpoints, e => e.Metadata.GetMetadata() != null)); Assert.Equal("/server", endpoint.RoutePattern.RawText); @@ -187,18 +161,21 @@ public void ConfirmChangeTokenDisposedHotReload() // Make a modification and then perform a hot reload. endpointDataSource.Conventions.Add(builder => builder.Metadata.Add(new TestMetadata())); + HotReloadService.UpdateApplication(null); HotReloadService.ClearCache(null); // Confirm the change token is disposed after ClearCache - Assert.True(wrappedChangeTokenDisposable.IsDisposed); + Assert.True(changeToken.HasChanged); + Assert.Throws(() => changeTokenSource.Token); } private class TestMetadata { } - private ComponentApplicationBuilder CreateBuilder(params Type[] types) + private class TestAssembly : Assembly; + + private static void ConfigureBuilder(ComponentApplicationBuilder builder, params Type[] types) { - var builder = new ComponentApplicationBuilder(); builder.AddLibrary(new AssemblyComponentLibraryDescriptor( "TestAssembly", Array.Empty(), @@ -208,8 +185,11 @@ private ComponentApplicationBuilder CreateBuilder(params Type[] types) ComponentType = t, RenderMode = t.GetCustomAttribute() }).ToArray())); + } - return builder; + private static void ConfigureServerComponentBuilder(ComponentApplicationBuilder builder) + { + ConfigureBuilder(builder, typeof(ServerComponent)); } private IServiceProvider CreateServices(params Type[] types) @@ -227,16 +207,21 @@ private IServiceProvider CreateServices(params Type[] types) } private static RazorComponentEndpointDataSource CreateDataSource( - ComponentApplicationBuilder builder, IServiceProvider services, - IComponentRenderMode[] renderModes = null) + Action configureBuilder = null, + IComponentRenderMode[] renderModes = null, + HotReloadService hotReloadService = null) { var result = new RazorComponentEndpointDataSource( - builder, new[] { new MockEndpointProvider() }, new TestEndpointRouteBuilder(services), new RazorComponentEndpointFactory(), - new HotReloadService() { MetadataUpdateSupported = true }); + hotReloadService ?? new HotReloadService() { MetadataUpdateSupported = true }); + + if (configureBuilder is not null) + { + result.ComponentApplicationBuilderActions.Add(configureBuilder); + } if (renderModes != null) { diff --git a/src/aspnetcore/src/Components/Endpoints/test/RazorComponentEndpointDataSourceTest.cs b/src/aspnetcore/src/Components/Endpoints/test/RazorComponentEndpointDataSourceTest.cs index 52cd757d62a..26a154b2cb1 100644 --- a/src/aspnetcore/src/Components/Endpoints/test/RazorComponentEndpointDataSourceTest.cs +++ b/src/aspnetcore/src/Components/Endpoints/test/RazorComponentEndpointDataSourceTest.cs @@ -24,6 +24,11 @@ public class RazorComponentEndpointDataSourceTest public void RegistersEndpoints() { var endpointDataSource = CreateDataSource(); + endpointDataSource.ComponentApplicationBuilderActions.Add(builder => + { + var assembly = typeof(App).Assembly; + IRazorComponentApplication.GetBuilderForAssembly(builder, assembly); + }); var endpoints = endpointDataSource.Endpoints; @@ -33,10 +38,15 @@ public void RegistersEndpoints() [Fact] public void NoDiscoveredModesDefaultsToStatic() { - - var builder = CreateBuilder(); var services = CreateServices(typeof(ServerEndpointProvider)); - var endpointDataSource = CreateDataSource(builder, services); + var endpointDataSource = CreateDataSource(services); + + endpointDataSource.ComponentApplicationBuilderActions.Add(builder => + { + builder.AddLibrary(new AssemblyComponentLibraryDescriptor( + "TestAssembly", + Array.Empty(), Array.Empty())); + }); var endpoints = endpointDataSource.Endpoints; @@ -199,22 +209,6 @@ public void NoDiscoveredModesDefaultsToStatic() }, }; - private ComponentApplicationBuilder CreateBuilder(params Type[] types) - { - var builder = new ComponentApplicationBuilder(); - builder.AddLibrary(new AssemblyComponentLibraryDescriptor( - "TestAssembly", - Array.Empty(), - types.Select(t => new ComponentBuilder - { - AssemblyName = "TestAssembly", - ComponentType = t, - RenderMode = t.GetCustomAttribute() - }).ToArray())); - - return builder; - } - private IServiceProvider CreateServices(params Type[] types) { var services = new ServiceCollection(); @@ -230,12 +224,10 @@ private IServiceProvider CreateServices(params Type[] types) } private RazorComponentEndpointDataSource CreateDataSource( - ComponentApplicationBuilder builder = null, IServiceProvider services = null, IComponentRenderMode[] renderModes = null) { var result = new RazorComponentEndpointDataSource( - builder ?? DefaultRazorComponentApplication.Instance.GetBuilder(), services?.GetService>() ?? Enumerable.Empty(), new TestEndpointRouteBuilder(services ?? CreateServices()), new RazorComponentEndpointFactory(), diff --git a/src/source-manifest.json b/src/source-manifest.json index 753a181d819..33dae99f271 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -7,10 +7,10 @@ "commitSha": "ba45f22d375e21c42fdc89695451932731d94552" }, { - "barId": 286219, + "barId": 286532, "path": "aspnetcore", "remoteUri": "https://github.com/dotnet/aspnetcore", - "commitSha": "305280b3a9092b709b4449640e4d8db9a327d46f" + "commitSha": "08964b968ed6d4381b74b05cb01afa8daeae5b6d" }, { "barId": 279211, From d7b32678f494ef2ae6a39182c46a8efceadcd6c4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 20:51:11 +0000 Subject: [PATCH 24/28] [release/10.0.1xx] Source code updates from dotnet/sdk (#2833) Co-authored-by: dotnet-maestro[bot] --- src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf | 2 +- src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf | 2 +- src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf | 2 +- src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf | 2 +- src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf | 2 +- src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf | 2 +- .../src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf | 2 +- .../src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf | 2 +- src/source-manifest.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index e2bb95312d1..6f0c0b4e099 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -2574,7 +2574,7 @@ Standardmäßig wird eine Framework-abhängige Anwendung veröffentlicht. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + Direktiven dürfen derzeit keine doppelten Anführungszeichen (") enthalten. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index 2446c0253eb..8fc261f14d5 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -2574,7 +2574,7 @@ El valor predeterminado es publicar una aplicación dependiente del marco. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + Las directivas no pueden contener comillas dobles ("), por ahora. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index 710630a9a7f..3d8be0107a5 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -2574,7 +2574,7 @@ La valeur par défaut est de publier une application dépendante du framework. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + Les directives ne peuvent actuellement pas contenir de guillemets doubles ("). diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index 69b69e64182..ff2e8c98609 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -2574,7 +2574,7 @@ Per impostazione predefinita, viene generato un pacchetto dipendente dal framewo Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + Le direttive attualmente non possono contenere virgolette doppie ("). diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index e88469c1efc..bc9182e525a 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -2574,7 +2574,7 @@ Domyślnie publikowana jest aplikacja zależna od struktury. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + Dyrektywy nie mogą obecnie zawierać podwójnych cudzysłowów ("). diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index bab1f4575a7..694c6428205 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -2574,7 +2574,7 @@ The default is to publish a framework-dependent application. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + В директивах пока нельзя использовать двойные кавычки ("). diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index bf50f4c94c5..725ed5df548 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -2574,7 +2574,7 @@ The default is to publish a framework-dependent application. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + 指令当前不能包含双引号(")。 diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index 31bed5db183..db6fc4bd2dd 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -2574,7 +2574,7 @@ The default is to publish a framework-dependent application. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + 指令目前不能包含雙引號 (")。 diff --git a/src/source-manifest.json b/src/source-manifest.json index 33dae99f271..612a9ee28ec 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -91,10 +91,10 @@ "commitSha": "082359066ee0064039b9b1f1f025bdd0507d06de" }, { - "barId": 286464, + "barId": 286541, "path": "sdk", "remoteUri": "https://github.com/dotnet/sdk", - "commitSha": "100134337cdbc0edb7a9a477b30ecc61f49bc92e" + "commitSha": "1f4cb4e96d32fd82e896fc7ddb13591c1d5cd956" }, { "barId": 282656, From 4d4ecf41b73cad0b10fe827320ae72efdcca6938 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 12 Oct 2025 09:47:29 -0700 Subject: [PATCH 25/28] [release/10.0.1xx] Source code updates from dotnet/sdk (#2837) Co-authored-by: dotnet-maestro[bot] --- .../Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf | 2 +- .../Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf | 2 +- .../Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf | 2 +- .../dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf | 2 +- .../Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf | 2 +- ...osoft.NET.WindowsSdkSupportedTargetPlatforms.props | 11 ++++++----- src/source-manifest.json | 4 ++-- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index 17ecd6053ba..aaea01228d5 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -2574,7 +2574,7 @@ Ve výchozím nastavení je publikována aplikace závislá na architektuře. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + Direktivy v současné době nemůžou obsahovat dvojité uvozovky ("). diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index 4a83f985e87..40678fb35f7 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -2574,7 +2574,7 @@ The default is to publish a framework-dependent application. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + ディレクティブには二重引用符 (") を含めることはできません。 diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index f96a7af1b6f..b2f6c81c0d2 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -2574,7 +2574,7 @@ The default is to publish a framework-dependent application. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + 지시문은 현재 큰따옴표(")를 포함할 수 없습니다. diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index 52b11f5c695..be9c08f1ce8 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -2574,7 +2574,7 @@ O padrão é publicar uma aplicação dependente de framework. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + No momento, as diretivas não podem conter aspas duplas ("). diff --git a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index 1f1f787d8af..f5b9e9b3825 100644 --- a/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/sdk/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -2574,7 +2574,7 @@ Varsayılan durum, çerçeveye bağımlı bir uygulama yayımlamaktır. Directives currently cannot contain double quotes ("). - Directives currently cannot contain double quotes ("). + Yönergeler şu anda çift tırnak (") içeremez. diff --git a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.WindowsSdkSupportedTargetPlatforms.props b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.WindowsSdkSupportedTargetPlatforms.props index 0a33b09d81f..3062e1d926b 100644 --- a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.WindowsSdkSupportedTargetPlatforms.props +++ b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.WindowsSdkSupportedTargetPlatforms.props @@ -24,10 +24,11 @@ Copyright (c) .NET Foundation. All rights reserved. - <_NormalizedWindowsSdkSupportedTargetPlatformVersion Include="@(WindowsSdkSupportedTargetPlatformVersion)"> - $([System.Version]::Parse('%(Identity)').Major).$([System.Version]::Parse('%(Identity)').Minor).$([System.Version]::Parse('%(Identity)').Build).0 - - + <_NormalizedWindowsSdkSupportedTargetPlatformVersion Include="@(WindowsSdkSupportedTargetPlatformVersion)"> + $([System.Text.RegularExpressions.Regex]::Replace(%(Identity), '^((\d+\.){3})1$', '${1}0')) + + diff --git a/src/source-manifest.json b/src/source-manifest.json index 612a9ee28ec..b3c5eff42e4 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -91,10 +91,10 @@ "commitSha": "082359066ee0064039b9b1f1f025bdd0507d06de" }, { - "barId": 286541, + "barId": 286627, "path": "sdk", "remoteUri": "https://github.com/dotnet/sdk", - "commitSha": "1f4cb4e96d32fd82e896fc7ddb13591c1d5cd956" + "commitSha": "09b6a7d0d679cf9480932424ae025e83c49fd9f6" }, { "barId": 282656, From 1b099651df3d8ddfd3427d4598587ae1ccdf599b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 12 Oct 2025 09:48:02 -0700 Subject: [PATCH 26/28] [release/10.0.1xx] Source code updates from dotnet/efcore (#2838) Co-authored-by: dotnet-maestro[bot] --- src/efcore/.config/guardian/.gdnbaselines | 106 +++++++++++ src/efcore/.config/guardian/gdnbaselines | 26 --- src/efcore/EFCore.sln | 5 +- src/efcore/azure-pipelines-internal-tests.yml | 107 ++++------- src/efcore/azure-pipelines-public.yml | 1 + src/efcore/azure-pipelines.yml | 173 +----------------- src/efcore/eng/Version.Details.props | 36 ++-- src/efcore/eng/Version.Details.xml | 74 ++++---- src/efcore/global.json | 4 +- src/source-manifest.json | 4 +- 10 files changed, 214 insertions(+), 322 deletions(-) create mode 100644 src/efcore/.config/guardian/.gdnbaselines delete mode 100644 src/efcore/.config/guardian/gdnbaselines diff --git a/src/efcore/.config/guardian/.gdnbaselines b/src/efcore/.config/guardian/.gdnbaselines new file mode 100644 index 00000000000..b6b74d33542 --- /dev/null +++ b/src/efcore/.config/guardian/.gdnbaselines @@ -0,0 +1,106 @@ +{ + "hydrated": false, + "properties": { + "helpUri": "https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/microsoft-guardian/general/baselines" + }, + "version": "1.0.0", + "baselines": { + "default": { + "name": "default", + "createdDate": "2025-10-09 21:18:42Z", + "lastUpdatedDate": "2025-10-09 21:18:42Z" + } + }, + "results": { + "9d8334bec997ff899ba849d8b31406f7c95af0ffb1d237972bd5134b8c6a9b88": { + "signature": "9d8334bec997ff899ba849d8b31406f7c95af0ffb1d237972bd5134b8c6a9b88", + "alternativeSignatures": [ + "b6a603191b00edf78ad2c6116a7a7822864031cc001884be25b3c1543dbe20a7" + ], + "memberOf": [ + "default" + ], + "createdDate": "2025-10-09 21:18:42Z" + }, + "ba7df56f5519347813a7917091709adf2d27b3493d05af0fb8b7037eda3020bb": { + "signature": "ba7df56f5519347813a7917091709adf2d27b3493d05af0fb8b7037eda3020bb", + "alternativeSignatures": [ + "5269e81e8a286ccd1568a00c455c489efa62e6887bfb55ea0dddaceb7183c882" + ], + "memberOf": [ + "default" + ], + "createdDate": "2025-10-09 21:18:42Z" + }, + "bc04851b7440a10a0c2a03f2793ab06b6562fe0529e0d353765503f1bcaf8c46": { + "signature": "bc04851b7440a10a0c2a03f2793ab06b6562fe0529e0d353765503f1bcaf8c46", + "alternativeSignatures": [ + "274b9a26e35f9604cd1c84941eb97f2edaecde6607be139e9d9d687f7d6875f4" + ], + "memberOf": [ + "default" + ], + "createdDate": "2025-10-09 21:18:42Z" + }, + "9fb27502e61c5647554076d6603a1092943fb625efb6c53faa1042e0d7d217ce": { + "signature": "9fb27502e61c5647554076d6603a1092943fb625efb6c53faa1042e0d7d217ce", + "alternativeSignatures": [ + "3355e030588f68be29994a44e2b11079e90945e26c6397345d11424ce36cc5a1" + ], + "memberOf": [ + "default" + ], + "createdDate": "2025-10-09 21:18:42Z" + }, + "60f28802b8ac837691755554b460b422afaeb8dea2129097ab3b7e6c43076ea1": { + "signature": "60f28802b8ac837691755554b460b422afaeb8dea2129097ab3b7e6c43076ea1", + "alternativeSignatures": [ + "7a3aa28c8f6e629099ba288e1a78ddb3191def880ae018f7146b66689daca838" + ], + "memberOf": [ + "default" + ], + "createdDate": "2025-10-09 21:18:42Z" + }, + "3bc55e953e7199f08b4c174f6fb0f026db93865d22fc5ef535e2ba1172c8db03": { + "signature": "3bc55e953e7199f08b4c174f6fb0f026db93865d22fc5ef535e2ba1172c8db03", + "alternativeSignatures": [ + "fb3809bbf91d374d8872aa371ff0d8858232822571dae6f9e6cba6276892d953" + ], + "memberOf": [ + "default" + ], + "createdDate": "2025-10-09 21:18:42Z" + }, + "bd69975ed44d92efc4a265e13462b1471f292ad9e8566b0200b2df7786808469": { + "signature": "bd69975ed44d92efc4a265e13462b1471f292ad9e8566b0200b2df7786808469", + "alternativeSignatures": [ + "609bf3d92ef1f73cbe4d3fa001926c0e274b04f21bf6d103a39a64849437e7e3" + ], + "memberOf": [ + "default" + ], + "createdDate": "2025-10-09 21:18:42Z" + }, + "0b6a4ced009a4e3efdf4ad8f00c0b31ec0791249087560c5c6481ab2824a35a8": { + "signature": "0b6a4ced009a4e3efdf4ad8f00c0b31ec0791249087560c5c6481ab2824a35a8", + "alternativeSignatures": [ + "c19c086ed81a8e7d7877bb2fb5a9d7df126ad553cbdd32086694b927042adc0b" + ], + "memberOf": [ + "default" + ], + "createdDate": "2025-10-09 21:18:42Z" + }, + "c689fe4e10fee4bdd5a3d759c027be8b89d28303078f76bb5aeb20dc192215c9": { + "signature": "c689fe4e10fee4bdd5a3d759c027be8b89d28303078f76bb5aeb20dc192215c9", + "alternativeSignatures": [ + "4faf3b308c9131f0e11686d21fd36e1ef6779c394d37cfc43cd360b4bfb086f5" + ], + "memberOf": [ + "default" + ], + "createdDate": "2025-10-09 21:18:42Z" + } + } +} \ No newline at end of file diff --git a/src/efcore/.config/guardian/gdnbaselines b/src/efcore/.config/guardian/gdnbaselines deleted file mode 100644 index b0533e8bab7..00000000000 --- a/src/efcore/.config/guardian/gdnbaselines +++ /dev/null @@ -1,26 +0,0 @@ -{ - "hydrated": false, - "properties": { - "helpUri": "https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/microsoft-guardian/general/baselines" - }, - "version": "1.0.0", - "baselines": { - "default": { - "name": "default", - "createdDate": "2025-08-19 11:30:04Z", - "lastUpdatedDate": "2025-08-19 11:30:04Z" - } - }, - "results": { - "289457ef952517284338044be0d68120ad96554e2cd793b14a427b2208be2990": { - "signature": "289457ef952517284338044be0d68120ad96554e2cd793b14a427b2208be2990", - "alternativeSignatures": [ - "8b86228cd1b156622e76e1845b23b901cafd908a4dc0a7b7bdd5cdd714b726ab" - ], - "memberOf": [ - "default" - ], - "createdDate": "2025-08-19 11:30:04Z" - } - } -} diff --git a/src/efcore/EFCore.sln b/src/efcore/EFCore.sln index fecc4fafa42..91075f55dfd 100644 --- a/src/efcore/EFCore.sln +++ b/src/efcore/EFCore.sln @@ -1,11 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31521.260 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11026.189 MinimumVisualStudioVersion = 17.0.31521.260 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B9E4CC99-199C-4E3B-9EC5-D1FDFCD6C27B}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + azure-pipelines-internal-tests.yml = azure-pipelines-internal-tests.yml azure-pipelines-public.yml = azure-pipelines-public.yml azure-pipelines.yml = azure-pipelines.yml .github\copilot-instructions.md = .github\copilot-instructions.md diff --git a/src/efcore/azure-pipelines-internal-tests.yml b/src/efcore/azure-pipelines-internal-tests.yml index 5f14dbd13bf..2987ae059ef 100644 --- a/src/efcore/azure-pipelines-internal-tests.yml +++ b/src/efcore/azure-pipelines-internal-tests.yml @@ -1,8 +1,6 @@ variables: - name: _BuildConfig value: Release - - name: _TeamName - value: AspNetCore - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE value: true - name: _PublishUsingPipelines @@ -11,12 +9,6 @@ variables: value: https://localhost:8081 - name: _CosmosToken value: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw== - - ${{ if or(startswith(variables['Build.SourceBranch'], 'refs/heads/release/'), startswith(variables['Build.SourceBranch'], 'refs/heads/internal/release/'), eq(variables['Build.Reason'], 'Manual')) }}: - - name: PostBuildSign - value: false - - ${{ else }}: - - name: PostBuildSign - value: true - group: DotNet-HelixApi-Access - name: _InternalRuntimeDownloadArgs value: /p:DotNetRuntimeSourceFeed=https://ci.dot.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) @@ -47,7 +39,6 @@ extends: parameters: featureFlags: autoBaseline: false - usePrefastVersion3: true autoEnableRoslynWithNewRuleset: false sdl: createAdoIssuesForJustificationsForDisablement: false @@ -55,19 +46,46 @@ extends: name: $(DncEngInternalBuildPool) image: 1es-windows-2022 os: windows + enabled: false baseline: baselineFile: $(Build.SourcesDirectory)\.config\guardian\.gdnbaselines binskim: - scanOutputDirectoryOnly: true - preReleaseVersion: '4.3.1' - env: - GDN_EXTRACT_TOOLS: "binskim" - GDN_EXTRACT_TARGETS: true - GDN_EXTRACT_FILTER: "f|**\\*.zip;f|**\\*.nupkg;f|**\\*.vsix;f|**\\*.cspkg;f|**\\*.sfpkg;f|**\\*.package" + enabled: false + justificationForDisabling: 'NonProduction' policheck: - enabled: true + enabled: false + justificationForDisabling: 'NonProduction' tsa: - enabled: true + enabled: false + justificationForDisabling: 'NonProduction' + antimalwareScan: + enabled: false + justificationForDisabling: 'NonProduction' + prefast: + enabled: false + justificationForDisabling: 'NonProduction' + codeQL: + compiled: + enabled: false + justificationForDisabling: 'NonProduction' + psscriptanalyzer: + enabled: false + justificationForDisabling: 'NonProduction' + credscan: + enabled: false + justificationForDisabling: 'NonProduction' + spmi: + enabled: false + justificationForDisabling: 'NonProduction' + componentgovernance: + enabled: false + justificationForDisabling: 'NonProduction' + eslint: + enabled: false + justificationForDisabling: 'NonProduction' + armory: + enabled: false + justificationForDisabling: 'NonProduction' customBuildTags: - ES365AIMigrationTooling stages: @@ -78,10 +96,10 @@ extends: parameters: enableMicrobuild: true enablePublishBuildArtifacts: true - enablePublishBuildAssets: true + enablePublishBuildAssets: false enablePublishTestResults: true - enablePublishUsingPipelines: ${{ variables._PublishUsingPipelines }} publishAssetsImmediately: true + isAssetlessBuild: true enableTelemetry: true helixRepo: dotnet/efcore jobs: @@ -95,15 +113,6 @@ extends: - _InternalBuildArgs: '' # Rely on task Arcade injects, not auto-injected build step. - skipComponentGovernanceDetection: true - - ${{ if notin(variables['Build.Reason'], 'PullRequest') }}: - - _SignType: real - - _InternalBuildArgs: /p:DotNetSignType=$(_SignType) /p:TeamName=$(_TeamName) /p:DotNetPublishUsingPipelines=$(_PublishUsingPipelines) /p:OfficialBuildId=$(BUILD.BUILDNUMBER) - # Ignore test and infrastructure code. - - Codeql.SourceRoot: src - # CodeQL3000 needs this plumbed along as a variable to enable TSA. - - Codeql.TSAEnabled: true - # Default expects tsaoptions.json under SourceRoot. - - Codeql.TSAOptionsPath: '$(Build.SourcesDirectory)/.config/tsaoptions.json' steps: - task: NuGetCommand@2 displayName: 'Clear NuGet caches' @@ -125,25 +134,6 @@ extends: env: Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl) displayName: Build - - task: CopyFiles@2 - displayName: 'Copy binaries for publishing' - inputs: - Contents: | - artifacts/bin/**/?(*.dll|*.exe|*.pdb) - !artifacts/bin/*Tests/** - TargetFolder: $(Agent.TempDirectory)/BinArtifacts - templateContext: - outputs: - - output: pipelineArtifact - displayName: Publish binaries - condition: always() - path: $(Agent.TempDirectory)/BinArtifacts/ - artifact: BinArtifacts - - output: pipelineArtifact - displayName: Upload TestResults - condition: always() - path: artifacts/TestResults/$(_BuildConfig)/ - artifact: $(Agent.Os)_$(Agent.JobName) TestResults - job: macOS pool: name: Azure Pipelines @@ -161,13 +151,6 @@ extends: # Work-around for https://github.com/dotnet/runtime/issues/70758 COMPlus_EnableWriteXorExecute: 0 displayName: Build - templateContext: - outputs: - - output: pipelineArtifact - displayName: Upload TestResults - condition: always() - path: artifacts/TestResults/$(_BuildConfig)/ - artifact: $(Agent.Os)_$(Agent.JobName) TestResults - job: Linux timeoutInMinutes: 180 pool: @@ -213,12 +196,6 @@ extends: sdl: binskim: prereleaseVersion: ' ' - outputs: - - output: pipelineArtifact - displayName: Upload TestResults - condition: always() - path: artifacts/TestResults/$(_BuildConfig)/ - artifact: $(Agent.Os)_$(Agent.JobName) TestResults - job: Helix timeoutInMinutes: 180 pool: @@ -266,13 +243,3 @@ extends: # Work-around for https://github.com/dotnet/runtime/issues/70758 COMPlus_EnableWriteXorExecute: 0 DotNetBuildsInternalReadSasToken: $(dotnetbuilds-internal-container-read-token) - - ${{ if notin(variables['Build.Reason'], 'PullRequest') }}: - - template: /eng/common/templates-official/post-build/post-build.yml@self - parameters: - publishingInfraVersion: 3 - enableSigningValidation: false - enableNugetValidation: false - enableSourceLinkValidation: false - publishAssetsImmediately: true - SDLValidationParameters: - enable: false diff --git a/src/efcore/azure-pipelines-public.yml b/src/efcore/azure-pipelines-public.yml index 6a3bf435d1d..70d4bdfdb3f 100644 --- a/src/efcore/azure-pipelines-public.yml +++ b/src/efcore/azure-pipelines-public.yml @@ -45,6 +45,7 @@ stages: enablePublishBuildAssets: true enablePublishUsingPipelines: ${{ variables._PublishUsingPipelines }} publishAssetsImmediately: true + isAssetlessBuild: true enableSourceIndex: false enableTelemetry: true helixRepo: dotnet/efcore diff --git a/src/efcore/azure-pipelines.yml b/src/efcore/azure-pipelines.yml index 5f14dbd13bf..510a2ff8ce6 100644 --- a/src/efcore/azure-pipelines.yml +++ b/src/efcore/azure-pipelines.yml @@ -6,11 +6,7 @@ variables: - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE value: true - name: _PublishUsingPipelines - value: true - - name: _CosmosConnectionUrl - value: https://localhost:8081 - - name: _CosmosToken - value: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw== + value: false - ${{ if or(startswith(variables['Build.SourceBranch'], 'refs/heads/release/'), startswith(variables['Build.SourceBranch'], 'refs/heads/internal/release/'), eq(variables['Build.Reason'], 'Manual')) }}: - name: PostBuildSign value: false @@ -59,6 +55,7 @@ extends: baselineFile: $(Build.SourcesDirectory)\.config\guardian\.gdnbaselines binskim: scanOutputDirectoryOnly: true + analyzeTargetGlob: '+:f|artifacts/bin/**/Microsoft.EntityFrameworkCore*.dll;+:f|artifacts/bin/**/Microsoft.Data.Sqlite*.dll;+:f|artifacts/bin/**/ef.exe;+:f|artifacts/bin/**/dotnet-ef.exe;-:f|artifacts/bin/**/shims/**/*.exe;' preReleaseVersion: '4.3.1' env: GDN_EXTRACT_TOOLS: "binskim" @@ -78,10 +75,10 @@ extends: parameters: enableMicrobuild: true enablePublishBuildArtifacts: true - enablePublishBuildAssets: true - enablePublishTestResults: true - enablePublishUsingPipelines: ${{ variables._PublishUsingPipelines }} + enablePublishBuildAssets: false + enablePublishTestResults: false publishAssetsImmediately: true + isAssetlessBuild: true enableTelemetry: true helixRepo: dotnet/efcore jobs: @@ -90,13 +87,14 @@ extends: name: $(DncEngInternalBuildPool) demands: ImageOverride -equals 1es-windows-2022 os: windows - timeoutInMinutes: 180 + timeoutInMinutes: 60 variables: - _InternalBuildArgs: '' # Rely on task Arcade injects, not auto-injected build step. - skipComponentGovernanceDetection: true - ${{ if notin(variables['Build.Reason'], 'PullRequest') }}: - _SignType: real + - _Sign: true - _InternalBuildArgs: /p:DotNetSignType=$(_SignType) /p:TeamName=$(_TeamName) /p:DotNetPublishUsingPipelines=$(_PublishUsingPipelines) /p:OfficialBuildId=$(BUILD.BUILDNUMBER) # Ignore test and infrastructure code. - Codeql.SourceRoot: src @@ -117,162 +115,7 @@ extends: - script: "echo ##vso[build.addbuildtag]release-candidate" condition: and(notin(variables['Build.Reason'], 'PullRequest'), eq(variables['IsFinalBuild'], 'true')) displayName: 'Set CI tags' - - powershell: SqlLocalDB start - displayName: Start LocalDB - - template: /eng/common/templates-official/steps/enable-internal-sources.yml - - template: /eng/common/templates-official/steps/enable-internal-runtimes.yml - - script: eng\common\cibuild.cmd -configuration $(_BuildConfig) -prepareMachine $(_InternalBuildArgs) $(_InternalRuntimeDownloadArgs) - env: - Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl) - displayName: Build - - task: CopyFiles@2 - displayName: 'Copy binaries for publishing' - inputs: - Contents: | - artifacts/bin/**/?(*.dll|*.exe|*.pdb) - !artifacts/bin/*Tests/** - TargetFolder: $(Agent.TempDirectory)/BinArtifacts - templateContext: - outputs: - - output: pipelineArtifact - displayName: Publish binaries - condition: always() - path: $(Agent.TempDirectory)/BinArtifacts/ - artifact: BinArtifacts - - output: pipelineArtifact - displayName: Upload TestResults - condition: always() - path: artifacts/TestResults/$(_BuildConfig)/ - artifact: $(Agent.Os)_$(Agent.JobName) TestResults - - job: macOS - pool: - name: Azure Pipelines - image: macOS-13 - os: macOS - variables: - # Rely on task Arcade injects, not auto-injected build step. - - skipComponentGovernanceDetection: true - steps: - - template: /eng/common/templates-official/steps/enable-internal-sources.yml - - template: /eng/common/templates-official/steps/enable-internal-runtimes.yml - - script: eng/common/build.sh --restore --build --test --pack --ci --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs) - env: - Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl) - # Work-around for https://github.com/dotnet/runtime/issues/70758 - COMPlus_EnableWriteXorExecute: 0 - displayName: Build - templateContext: - outputs: - - output: pipelineArtifact - displayName: Upload TestResults - condition: always() - path: artifacts/TestResults/$(_BuildConfig)/ - artifact: $(Agent.Os)_$(Agent.JobName) TestResults - - job: Linux - timeoutInMinutes: 180 - pool: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals 1es-ubuntu-2204 - os: linux - variables: - - _runCounter: $[counter(variables['Build.Reason'], 0)] - # Rely on task Arcade injects, not auto-injected build step. - - skipComponentGovernanceDetection: true - - ${{ if notin(variables['Build.Reason'], 'PullRequest', 'Schedule') }}: - - _CosmosConnectionUrl: 'true' - steps: - - bash: | - echo "##vso[task.setvariable variable=_CosmosConnectionUrl]https://ef-nightly-test.documents.azure.com:443/" - displayName: Prepare to run Cosmos tests on ef-nightly-test - condition: and(eq(variables['_CosmosConnectionUrl'], 'true'), or(endsWith(variables['_runCounter'], '0'), endsWith(variables['_runCounter'], '2'), endsWith(variables['_runCounter'], '4'), endsWith(variables['_runCounter'], '6'), endsWith(variables['_runCounter'], '8'))) - - bash: | - echo "##vso[task.setvariable variable=_CosmosConnectionUrl]https://ef-pr-test.documents.azure.com:443/" - displayName: Prepare to run Cosmos tests on ef-pr-test - condition: and(eq(variables['_CosmosConnectionUrl'], 'true'), or(endsWith(variables['_runCounter'], '1'), endsWith(variables['_runCounter'], '3'), endsWith(variables['_runCounter'], '5'), endsWith(variables['_runCounter'], '7'), endsWith(variables['_runCounter'], '9'))) - template: /eng/common/templates-official/steps/enable-internal-sources.yml - template: /eng/common/templates-official/steps/enable-internal-runtimes.yml - - script: eng/common/build.sh --restore --build --test --pack --ci --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs) + - script: eng\common\build.cmd -restore -build -sign -pack -publish -ci -configuration $(_BuildConfig) -prepareMachine $(_InternalRuntimeDownloadArgs) displayName: Build - - task: AzureCLI@2 - displayName: Run Cosmos tests - condition: notin(variables['Build.Reason'], 'PullRequest', 'Schedule') - inputs: - azureSubscription: EFCosmosTesting - addSpnToEnvironment: true - scriptType: bash - scriptLocation: 'inlineScript' - inlineScript: | - ./test.sh --ci --configuration $(_BuildConfig) --projects $(Build.SourcesDirectory)/test/EFCore.Cosmos.FunctionalTests/EFCore.Cosmos.FunctionalTests.csproj - env: - Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl) - Test__Cosmos__UseTokenCredential: true - Test__Cosmos__SubscriptionId: d709b837-4a74-4aec-addc-b6e4b9b23e7e - Test__Cosmos__ResourceGroup: efcosmosci - name: Build - templateContext: - sdl: - binskim: - prereleaseVersion: ' ' - outputs: - - output: pipelineArtifact - displayName: Upload TestResults - condition: always() - path: artifacts/TestResults/$(_BuildConfig)/ - artifact: $(Agent.Os)_$(Agent.JobName) TestResults - - job: Helix - timeoutInMinutes: 180 - pool: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals 1es-windows-2022 - os: windows - variables: - # Rely on task Arcade injects, not auto-injected build step. - - skipComponentGovernanceDetection: true - - name: _HelixBuildConfig - value: $(_BuildConfig) - - name: HelixTargetQueues - value: Windows.10.Amd64;OSX.13.Amd64;OSX.13.ARM64;Ubuntu.2204.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-sqlserver-amd64 - - name: _HelixAccessToken - # Needed for internal queues - value: $(HelixApiAccessToken) - steps: - - task: NuGetCommand@2 - displayName: 'Clear NuGet caches' - condition: succeeded() - inputs: - command: custom - arguments: 'locals all -clear' - - template: /eng/common/templates-official/steps/enable-internal-sources.yml - - template: /eng/common/templates-official/steps/enable-internal-runtimes.yml - - ${{ if ne(variables['System.TeamProject'], 'public') }}: - - template: /eng/common/core-templates/steps/get-delegation-sas.yml - parameters: - federatedServiceConnection: 'dotnetbuilds-internal-read' - outputVariableName: 'dotnetbuilds-internal-container-read-token' - expiryInHours: 1 - base64Encode: false - storageAccount: dotnetbuilds - container: internal - permissions: rl - - script: restore.cmd -ci /p:configuration=$(_BuildConfig) $(_InternalRuntimeDownloadArgs) - displayName: Restore packages - - script: .dotnet\dotnet build eng\helix.proj /restore /t:Test /p:configuration=$(_BuildConfig) /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog $(_InternalRuntimeDownloadArgs) - displayName: Send job to helix - env: - HelixAccessToken: $(_HelixAccessToken) - # We need to set this env var to publish helix results to Azure Dev Ops - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - MSSQL_SA_PASSWORD: "PLACEHOLDERPass$$w0rd" - # Work-around for https://github.com/dotnet/runtime/issues/70758 - COMPlus_EnableWriteXorExecute: 0 - DotNetBuildsInternalReadSasToken: $(dotnetbuilds-internal-container-read-token) - - ${{ if notin(variables['Build.Reason'], 'PullRequest') }}: - - template: /eng/common/templates-official/post-build/post-build.yml@self - parameters: - publishingInfraVersion: 3 - enableSigningValidation: false - enableNugetValidation: false - enableSourceLinkValidation: false - publishAssetsImmediately: true - SDLValidationParameters: - enable: false diff --git a/src/efcore/eng/Version.Details.props b/src/efcore/eng/Version.Details.props index 70ce7292d37..397aed1c2f8 100644 --- a/src/efcore/eng/Version.Details.props +++ b/src/efcore/eng/Version.Details.props @@ -6,24 +6,24 @@ This file should be imported by eng/Versions.props - 10.0.0-beta.25507.103 - 10.0.0-beta.25507.103 - 10.0.0-beta.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 - 10.0.0-rtm.25507.103 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-beta.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 + 10.0.0-rtm.25509.106 diff --git a/src/efcore/eng/Version.Details.xml b/src/efcore/eng/Version.Details.xml index d04c92e1960..709bc9ecf05 100644 --- a/src/efcore/eng/Version.Details.xml +++ b/src/efcore/eng/Version.Details.xml @@ -1,80 +1,80 @@ - + - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac - + https://github.com/dotnet/dotnet - 915977521b41280adbe21a54345be23cb5bf3536 + f448387a0e80f2fdeaec2d2f99ace7284fe37aac diff --git a/src/efcore/global.json b/src/efcore/global.json index dffd3048bc8..a83f17df244 100644 --- a/src/efcore/global.json +++ b/src/efcore/global.json @@ -18,7 +18,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25507.103", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25507.103" + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25509.106", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25509.106" } } diff --git a/src/source-manifest.json b/src/source-manifest.json index b3c5eff42e4..76ca812877f 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -37,10 +37,10 @@ "commitSha": "f40e210b5da69e3c7585917137322cac01f0dffc" }, { - "barId": 286443, + "barId": 286575, "path": "efcore", "remoteUri": "https://github.com/dotnet/efcore", - "commitSha": "5457b1b858107bd3a0412810b7c665052df29b56" + "commitSha": "f07ec89c55b88de5b1992cbbed86ae0529f3307f" }, { "barId": 283436, From 38ee40a03916edd00f72b84677d04b112241be3f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 12 Oct 2025 09:48:25 -0700 Subject: [PATCH 27/28] [release/10.0.1xx] Source code updates from dotnet/runtime (#2835) Co-authored-by: dotnet-maestro[bot] --- src/runtime/src/coreclr/jit/lclmorph.cpp | 2 +- src/runtime/src/coreclr/vm/appdomain.cpp | 136 +++++++++++------- src/runtime/src/coreclr/vm/appdomain.hpp | 12 +- src/runtime/src/coreclr/vm/assemblyspec.hpp | 3 +- .../gen/JsonSourceGenerator.Emitter.cs | 21 ++- .../RealWorldContextTests.cs | 13 +- .../TestClasses.cs | 11 ++ .../CompilationHelper.cs | 72 +++++++++- .../JsonSourceGeneratorTests.cs | 134 +++++++++++++---- ...urceGeneration.Roslyn4.4.Unit.Tests.csproj | 2 +- .../JitBlue/Runtime_120414/Runtime_120414.cs | 26 ++++ .../Runtime_120414/Runtime_120414.csproj | 9 ++ .../src/tests/profiler/unittest/moduleload.cs | 16 ++- .../tests/profiler/unittest/moduleload.csproj | 1 + src/source-manifest.json | 4 +- 15 files changed, 368 insertions(+), 94 deletions(-) create mode 100644 src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_120414/Runtime_120414.cs create mode 100644 src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_120414/Runtime_120414.csproj diff --git a/src/runtime/src/coreclr/jit/lclmorph.cpp b/src/runtime/src/coreclr/jit/lclmorph.cpp index cd464797e79..ecb01980013 100644 --- a/src/runtime/src/coreclr/jit/lclmorph.cpp +++ b/src/runtime/src/coreclr/jit/lclmorph.cpp @@ -2020,7 +2020,7 @@ class LocalAddressVisitor final : public GenTreeVisitor } if ((genTypeSize(indir) == genTypeSize(varDsc)) && (genTypeSize(indir) <= TARGET_POINTER_SIZE) && - (varTypeIsFloating(indir) || varTypeIsFloating(varDsc))) + (varTypeIsFloating(indir) || varTypeIsFloating(varDsc)) && !varDsc->lvPromoted) { return IndirTransform::BitCast; } diff --git a/src/runtime/src/coreclr/vm/appdomain.cpp b/src/runtime/src/coreclr/vm/appdomain.cpp index 7b247b2b8bf..f7d01fd809a 100644 --- a/src/runtime/src/coreclr/vm/appdomain.cpp +++ b/src/runtime/src/coreclr/vm/appdomain.cpp @@ -1871,7 +1871,7 @@ DispIDCache* AppDomain::SetupRefDispIDCache() #endif // FEATURE_COMINTEROP -FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEAssembly * pPEAssembly, Assembly *pAssembly) +FileLoadLock* FileLoadLock::Create(PEFileListLock* pLock, PEAssembly* pPEAssembly) { CONTRACTL { @@ -1884,7 +1884,7 @@ FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEAssembly * pPEAssemb } CONTRACTL_END; - NewHolder result(new FileLoadLock(pLock, pPEAssembly, pAssembly)); + NewHolder result(new FileLoadLock(pLock, pPEAssembly)); pLock->AddElement(result); result->AddRef(); // Add one ref on behalf of the ListLock's reference. The corresponding Release() happens in FileLoadLock::CompleteLoadLevel. @@ -1910,6 +1910,14 @@ Assembly *FileLoadLock::GetAssembly() return m_pAssembly; } +PEAssembly* FileLoadLock::GetPEAssembly() +{ + LIMITED_METHOD_CONTRACT; + // Underlying PEAssembly pointer is stored in the constructor in base ListLockEntry::m_data. + _ASSERTE(m_data != NULL); + return (PEAssembly*)m_data; +} + FileLoadLevel FileLoadLock::GetLoadLevel() { LIMITED_METHOD_CONTRACT; @@ -1958,6 +1966,7 @@ BOOL FileLoadLock::CanAcquire(FileLoadLevel targetLevel) static const char *fileLoadLevelName[] = { "CREATE", // FILE_LOAD_CREATE + "ALLOCATE", // FILE_LOAD_ALLOCATE "BEGIN", // FILE_LOAD_BEGIN "BEFORE_TYPE_LOAD", // FILE_LOAD_BEFORE_TYPE_LOAD "EAGER_FIXUPS", // FILE_LOAD_EAGER_FIXUPS @@ -1983,7 +1992,9 @@ BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success) if (level > m_level) { // Must complete each level in turn, unless we have an error - CONSISTENCY_CHECK(m_pAssembly->IsError() || (level == (m_level+1))); + CONSISTENCY_CHECK((level == (m_level+1)) || (m_pAssembly != nullptr && m_pAssembly->IsError())); + CONSISTENCY_CHECK(m_pAssembly != nullptr || level < FILE_LOAD_ALLOCATE); + // Remove the lock from the list if the load is completed if (level >= FILE_ACTIVE) { @@ -2019,7 +2030,7 @@ BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success) { m_level = (FileLoadLevel)level; - if (success) + if (success && level >= FILE_LOAD_ALLOCATE) m_pAssembly->SetLoadLevel(level); } @@ -2042,6 +2053,18 @@ BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success) return FALSE; } +void FileLoadLock::SetAssembly(Assembly* pAssembly) +{ + LIMITED_METHOD_CONTRACT; + + _ASSERTE(HasLock()); + _ASSERTE(m_level == FILE_LOAD_CREATE); // Only valid to set during CREATE -> ALLOCATE + _ASSERTE(m_pAssembly == nullptr); + _ASSERTE(pAssembly != nullptr && pAssembly->GetPEAssembly() == (PEAssembly *)m_data); + + m_pAssembly = pAssembly; +} + void FileLoadLock::SetError(Exception *ex) { CONTRACTL @@ -2088,10 +2111,10 @@ UINT32 FileLoadLock::Release() return count; } -FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEAssembly * pPEAssembly, Assembly *pAssembly) +FileLoadLock::FileLoadLock(PEFileListLock* pLock, PEAssembly* pPEAssembly) : ListLockEntry(pLock, pPEAssembly, "File load lock"), m_level((FileLoadLevel) (FILE_LOAD_CREATE)), - m_pAssembly(pAssembly), + m_pAssembly(nullptr), m_cachedHR(S_OK) { WRAPPER_NO_CONTRACT; @@ -2420,23 +2443,6 @@ Assembly *AppDomain::LoadAssemblyInternal(AssemblySpec* pIdentity, if (result == NULL) { - LoaderAllocator *pLoaderAllocator = NULL; - - AssemblyBinder *pAssemblyBinder = pPEAssembly->GetAssemblyBinder(); - // Assemblies loaded with CustomAssemblyBinder need to use a different LoaderAllocator if - // marked as collectible - pLoaderAllocator = pAssemblyBinder->GetLoaderAllocator(); - if (pLoaderAllocator == NULL) - { - pLoaderAllocator = this->GetLoaderAllocator(); - } - - // Allocate the DomainAssembly a bit early to avoid GC mode problems. We could potentially avoid - // a rare redundant allocation by moving this closer to FileLoadLock::Create, but it's not worth it. - AllocMemTracker amTracker; - AllocMemTracker *pamTracker = &amTracker; - NewHolder pDomainAssembly = new DomainAssembly(pPEAssembly, pLoaderAllocator, pamTracker); - LoadLockHolder lock(this); // Find the list lock entry @@ -2448,20 +2454,9 @@ Assembly *AppDomain::LoadAssemblyInternal(AssemblySpec* pIdentity, result = FindAssembly(pPEAssembly, FindAssemblyOptions_IncludeFailedToLoad); if (result == NULL) { - // We are the first one in - create the DomainAssembly + // We are the first one in - create the FileLoadLock. Creation of the Assembly will happen at FILE_LOAD_ALLOCATE stage registerNewAssembly = true; - fileLock = FileLoadLock::Create(lock, pPEAssembly, pDomainAssembly->GetAssembly()); - pDomainAssembly.SuppressRelease(); - pamTracker->SuppressRelease(); - - // Set the assembly module to be tenured now that we know it won't be deleted - pDomainAssembly->GetAssembly()->SetIsTenured(); - if (pDomainAssembly->GetAssembly()->IsCollectible()) - { - // We add the assembly to the LoaderAllocator only when we are sure that it can be added - // and won't be deleted in case of a concurrent load from the same ALC - ((AssemblyLoaderAllocator *)pLoaderAllocator)->AddDomainAssembly(pDomainAssembly); - } + fileLock = FileLoadLock::Create(lock, pPEAssembly); } } else @@ -2479,6 +2474,8 @@ Assembly *AppDomain::LoadAssemblyInternal(AssemblySpec* pIdentity, // so it will not be removed until app domain unload. So there is no need // to release our ref count. result = LoadAssembly(fileLock, targetLevel); + // By now FILE_LOAD_ALLOCATE should have run and the Assembly should exist + _ASSERTE(result != NULL); } else { @@ -2487,7 +2484,7 @@ Assembly *AppDomain::LoadAssemblyInternal(AssemblySpec* pIdentity, if (registerNewAssembly) { - pPEAssembly->GetAssemblyBinder()->AddLoadedAssembly(pDomainAssembly->GetAssembly()); + pPEAssembly->GetAssemblyBinder()->AddLoadedAssembly(result); } } else @@ -2517,6 +2514,7 @@ Assembly *AppDomain::LoadAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel STANDARD_VM_CHECK; PRECONDITION(CheckPointer(pLock)); PRECONDITION(AppDomain::GetCurrentDomain() == this); + PRECONDITION(targetLevel >= FILE_LOAD_ALLOCATE); POSTCONDITION(RETVAL->GetLoadLevel() >= GetCurrentFileLoadLevel() || RETVAL->GetLoadLevel() >= targetLevel); POSTCONDITION(RETVAL->CheckNoError(targetLevel)); @@ -2531,6 +2529,7 @@ Assembly *AppDomain::LoadAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel // Do a quick out check for the already loaded case. if (pLock->GetLoadLevel() >= targetLevel) { + _ASSERTE(pAssembly != nullptr); pAssembly->ThrowIfError(targetLevel); RETURN pAssembly; @@ -2553,8 +2552,9 @@ Assembly *AppDomain::LoadAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel if (immediateTargetLevel > limit.GetLoadLevel()) immediateTargetLevel = limit.GetLoadLevel(); + const char *simpleName = pLock->GetPEAssembly()->GetSimpleName(); LOG((LF_LOADER, LL_INFO100, "LOADER: ***%s*\t>>>Load initiated, %s/%s\n", - pAssembly->GetSimpleName(), + simpleName, fileLoadLevelName[immediateTargetLevel], fileLoadLevelName[targetLevel])); // Now loop and do the load incrementally to the target level. @@ -2577,30 +2577,32 @@ Assembly *AppDomain::LoadAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel LOG((LF_LOADER, (workLevel == FILE_LOAD_BEGIN - || workLevel == FILE_LOADED - || workLevel == FILE_ACTIVE) - ? LL_INFO10 : LL_INFO1000, - "LOADER: %p:***%s*\t loading at level %s\n", - this, pAssembly->GetSimpleName(), fileLoadLevelName[workLevel])); + || workLevel == FILE_LOADED + || workLevel == FILE_ACTIVE) + ? LL_INFO10 : LL_INFO1000, + "LOADER: %p:***%s*\t loading at level %s\n", + this, simpleName, fileLoadLevelName[workLevel])); - TryIncrementalLoad(pAssembly, workLevel, fileLock); + TryIncrementalLoad(workLevel, fileLock); } } if (pLock->GetLoadLevel() == immediateTargetLevel-1) { LOG((LF_LOADER, LL_INFO100, "LOADER: ***%s*\t<<GetSimpleName(), + simpleName, fileLoadLevelName[immediateTargetLevel-1])); } } LOG((LF_LOADER, LL_INFO100, "LOADER: ***%s*\t<<GetSimpleName(), + simpleName, fileLoadLevelName[pLock->GetLoadLevel()])); - } + pAssembly = pLock->GetAssembly(); + _ASSERTE(pAssembly != nullptr); // We should always be loading to at least FILE_LOAD_ALLOCATE, so the assembly should be created + // There may have been an error stored on the domain file by another thread, or from a previous load pAssembly->ThrowIfError(targetLevel); @@ -2624,7 +2626,7 @@ Assembly *AppDomain::LoadAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel RETURN pAssembly; } -void AppDomain::TryIncrementalLoad(Assembly *pAssembly, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder) +void AppDomain::TryIncrementalLoad(FileLoadLevel workLevel, FileLoadLockHolder& lockHolder) { STANDARD_VM_CONTRACT; @@ -2632,11 +2634,41 @@ void AppDomain::TryIncrementalLoad(Assembly *pAssembly, FileLoadLevel workLevel, BOOL released = FALSE; FileLoadLock* pLoadLock = lockHolder.GetValue(); + Assembly* pAssembly = pLoadLock->GetAssembly(); EX_TRY { - // Do the work - BOOL success = pAssembly->DoIncrementalLoad(workLevel); + BOOL success; + if (workLevel == FILE_LOAD_ALLOCATE) + { + // FileLoadLock should not have an assembly yet + _ASSERTE(pAssembly == NULL); + + // Allocate DomainAssembly & Assembly + PEAssembly *pPEAssembly = pLoadLock->GetPEAssembly(); + AssemblyBinder *pAssemblyBinder = pPEAssembly->GetAssemblyBinder(); + LoaderAllocator *pLoaderAllocator = pAssemblyBinder->GetLoaderAllocator(); + if (pLoaderAllocator == NULL) + pLoaderAllocator = this->GetLoaderAllocator(); + + AllocMemTracker amTracker; + AllocMemTracker *pamTracker = &amTracker; + NewHolder pDomainAssembly = new DomainAssembly(pPEAssembly, pLoaderAllocator, pamTracker); + pLoadLock->SetAssembly(pDomainAssembly->GetAssembly()); + pDomainAssembly->GetAssembly()->SetIsTenured(); + if (pDomainAssembly->GetAssembly()->IsCollectible()) + { + ((AssemblyLoaderAllocator *)pLoaderAllocator)->AddDomainAssembly(pDomainAssembly); + } + pDomainAssembly.SuppressRelease(); + pamTracker->SuppressRelease(); + pAssembly = pLoadLock->GetAssembly(); + success = TRUE; + } + else + { + success = pAssembly->DoIncrementalLoad(workLevel); + } // Complete the level. if (pLoadLock->CompleteLoadLevel(workLevel, success) && @@ -2651,9 +2683,9 @@ void AppDomain::TryIncrementalLoad(Assembly *pAssembly, FileLoadLevel workLevel, { Exception *pEx = GET_EXCEPTION(); - //We will cache this error and wire this load to forever fail, + // We will cache this error and wire this load to forever fail, // unless the exception is transient or the file is loaded OK but just cannot execute - if (!pEx->IsTransient() && !pAssembly->IsLoaded()) + if (pAssembly != nullptr && !pEx->IsTransient() && !pAssembly->IsLoaded()) { if (released) { diff --git a/src/runtime/src/coreclr/vm/appdomain.hpp b/src/runtime/src/coreclr/vm/appdomain.hpp index 8a42c4d7cd2..a58a2314ee0 100644 --- a/src/runtime/src/coreclr/vm/appdomain.hpp +++ b/src/runtime/src/coreclr/vm/appdomain.hpp @@ -293,14 +293,15 @@ class FileLoadLock : public ListLockEntry { private: FileLoadLevel m_level; - Assembly* m_pAssembly; + Assembly* m_pAssembly; // Will be null until FILE_LOAD_ALLOCATE is completed successfully HRESULT m_cachedHR; public: - static FileLoadLock *Create(PEFileListLock *pLock, PEAssembly *pPEAssembly, Assembly *pAssembly); + static FileLoadLock* Create(PEFileListLock* pLock, PEAssembly* pPEAssembly); ~FileLoadLock(); Assembly *GetAssembly(); + PEAssembly* GetPEAssembly(); FileLoadLevel GetLoadLevel(); // CanAcquire will return FALSE if Acquire will definitely not take the lock due @@ -320,6 +321,9 @@ class FileLoadLock : public ListLockEntry // returns TRUE if it updated load level, FALSE if the level was set already BOOL CompleteLoadLevel(FileLoadLevel level, BOOL success); + // Associate an Assembly with this lock + void SetAssembly(Assembly* pAssembly); + void SetError(Exception *ex); void AddRef(); @@ -327,7 +331,7 @@ class FileLoadLock : public ListLockEntry private: - FileLoadLock(PEFileListLock *pLock, PEAssembly *pPEAssembly, Assembly *pAssembly); + FileLoadLock(PEFileListLock* pLock, PEAssembly* pPEAssembly); static void HolderLeave(FileLoadLock *pThis); @@ -1098,7 +1102,7 @@ class AppDomain final Assembly *LoadAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel); - void TryIncrementalLoad(Assembly *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder); + void TryIncrementalLoad(FileLoadLevel workLevel, FileLoadLockHolder& lockHolder); #ifndef DACCESS_COMPILE // needs AssemblySpec public: diff --git a/src/runtime/src/coreclr/vm/assemblyspec.hpp b/src/runtime/src/coreclr/vm/assemblyspec.hpp index ea94c25dbbf..49446800fe7 100644 --- a/src/runtime/src/coreclr/vm/assemblyspec.hpp +++ b/src/runtime/src/coreclr/vm/assemblyspec.hpp @@ -27,7 +27,8 @@ enum FileLoadLevel // Note that semantics here are description is the LAST step done, not what is // currently being done. - FILE_LOAD_CREATE, + FILE_LOAD_CREATE, // List entry + FileLoadLock created, no Assembly/DomainAssembly yet + FILE_LOAD_ALLOCATE, // DomainAssembly & Assembly object allocated and associated with the lock FILE_LOAD_BEGIN, FILE_LOAD_BEFORE_TYPE_LOAD, FILE_LOAD_EAGER_FIXUPS, diff --git a/src/runtime/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/runtime/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index 80b648dfd95..879b41e23c3 100644 --- a/src/runtime/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/runtime/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -612,7 +612,17 @@ private void GeneratePropMetadataInitFunc(SourceWriter writer, string propInitMe PropertyGenerationSpec property = properties[i]; string propertyName = property.NameSpecifiedInSourceCode; string declaringTypeFQN = property.DeclaringType.FullyQualifiedName; - string propertyTypeFQN = property.PropertyType.FullyQualifiedName; + + // If the property is ignored and its type is not used anywhere else in the type graph, + // emit a JsonPropertyInfo of type 'object' to avoid unnecessarily referencing the type. + // STJ requires that all ignored properties be included so that it can perform + // necessary run-time validations using configuration not known at compile time + // such as the property naming policy and case sensitivity. + bool isIgnoredPropertyOfUnusedType = + property.DefaultIgnoreCondition is JsonIgnoreCondition.Always && + !_typeIndex.ContainsKey(property.PropertyType); + + string propertyTypeFQN = isIgnoredPropertyOfUnusedType ? "object" : property.PropertyType.FullyQualifiedName; string getterValue = property switch { @@ -653,9 +663,12 @@ private void GeneratePropMetadataInitFunc(SourceWriter writer, string propInitMe : $"({JsonConverterTypeRef}<{propertyTypeFQN}>){ExpandConverterMethodName}(typeof({propertyTypeFQN}), new {converterFQN}(), {OptionsLocalVariableName})"; } - string attributeProviderFactoryExpr = property.IsProperty - ? $"typeof({property.DeclaringType.FullyQualifiedName}).GetProperty({FormatStringLiteral(property.MemberName)}, {InstanceMemberBindingFlagsVariableName}, null, typeof({property.PropertyType.FullyQualifiedName}), {EmptyTypeArray}, null)" - : $"typeof({property.DeclaringType.FullyQualifiedName}).GetField({FormatStringLiteral(property.MemberName)}, {InstanceMemberBindingFlagsVariableName})"; + string attributeProviderFactoryExpr = property switch + { + _ when isIgnoredPropertyOfUnusedType => "null", + { IsProperty: true } => $"typeof({property.DeclaringType.FullyQualifiedName}).GetProperty({FormatStringLiteral(property.MemberName)}, {InstanceMemberBindingFlagsVariableName}, null, typeof({propertyTypeFQN}), {EmptyTypeArray}, null)", + _ => $"typeof({property.DeclaringType.FullyQualifiedName}).GetField({FormatStringLiteral(property.MemberName)}, {InstanceMemberBindingFlagsVariableName})", + }; writer.WriteLine($$""" var {{InfoVarName}}{{i}} = new {{JsonPropertyInfoValuesTypeRef}}<{{propertyTypeFQN}}> diff --git a/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs b/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs index c058cf81a3d..e30fafc95d2 100644 --- a/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs +++ b/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs @@ -1122,6 +1122,7 @@ public void NumberHandlingHonoredOnPoco() [InlineData(MemberTypes.Field, nameof(PocoWithMixedVisibilityMembers.FieldWithCustomName), "customField")] [InlineData(MemberTypes.Property, nameof(PocoWithMixedVisibilityMembers.BaseProperty))] [InlineData(MemberTypes.Property, nameof(PocoWithMixedVisibilityMembers.ShadowProperty))] + [InlineData(MemberTypes.Property, nameof(PocoWithMixedVisibilityMembers.ExperimentalProperty))] public void JsonPropertyInfo_PopulatesAttributeProvider(MemberTypes memberType, string propertyName, string? jsonPropertyName = null) { if (DefaultContext.JsonSourceGenerationMode is JsonSourceGenerationMode.Serialization) @@ -1134,7 +1135,17 @@ public void JsonPropertyInfo_PopulatesAttributeProvider(MemberTypes memberType, JsonPropertyInfo prop = typeInfo.Properties.FirstOrDefault(prop => prop.Name == name); Assert.NotNull(prop); - MemberInfo memberInfo = Assert.IsAssignableFrom(prop.AttributeProvider); + MemberInfo memberInfo; + if (prop.AttributeProvider is null) + { + Assert.Equal(typeof(object), prop.PropertyType); + memberInfo = typeof(PocoWithMixedVisibilityMembers).GetMember(propertyName, memberType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Single(); + Type actualPropertyType = memberInfo is PropertyInfo pInfo ? pInfo.PropertyType : ((FieldInfo)memberInfo).FieldType; + Assert.False(typeInfo.Options.TryGetTypeInfo(actualPropertyType, out _)); + return; + } + + memberInfo = Assert.IsAssignableFrom(prop.AttributeProvider); string? actualJsonPropertyName = memberInfo.GetCustomAttribute()?.Name; Assert.True(memberInfo.DeclaringType.IsAssignableFrom(typeInfo.Type)); diff --git a/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/TestClasses.cs b/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/TestClasses.cs index b6f2be92175..5f542807d1f 100644 --- a/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/TestClasses.cs +++ b/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/TestClasses.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using Microsoft.Extensions.Primitives; @@ -332,8 +333,18 @@ public class PocoWithMixedVisibilityMembers : PocoWithMixedVisibilityMembersBase public string FieldWithCustomName; public new int ShadowProperty { get; set; } + +#pragma warning disable EXP0001 + [JsonIgnore] + public ExperimentalClass ExperimentalProperty { get; set; } +#pragma warning restore EXP0001 } +#if NET + [Experimental("EXP0001")] +#endif + public class ExperimentalClass; + public sealed class ClassWithConflictingIgnoredProperties { [JsonIgnore] diff --git a/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs b/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs index 37f6c74e172..9db17588627 100644 --- a/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs +++ b/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; using Xunit; +using Xunit.Abstractions; namespace System.Text.Json.SourceGeneration.UnitTests { @@ -133,7 +134,10 @@ public static CSharpGeneratorDriver CreateJsonSourceGeneratorDriver(Compilation #endif } - public static JsonSourceGeneratorResult RunJsonSourceGenerator(Compilation compilation, bool disableDiagnosticValidation = false) + public static JsonSourceGeneratorResult RunJsonSourceGenerator( + Compilation compilation, + bool disableDiagnosticValidation = false, + ITestOutputHelper? logger = null) { var generatedSpecs = ImmutableArray.Empty; var generator = new JsonSourceGenerator @@ -144,6 +148,19 @@ public static JsonSourceGeneratorResult RunJsonSourceGenerator(Compilation compi CSharpGeneratorDriver driver = CreateJsonSourceGeneratorDriver(compilation, generator); driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outCompilation, out ImmutableArray diagnostics); + if (logger is not null) + { + foreach (Diagnostic diagnostic in outCompilation.GetDiagnostics().Concat(diagnostics)) + { + logger.WriteLine(diagnostic.ToString()); + } + + foreach (var tree in outCompilation.SyntaxTrees) + { + LogGeneratedCode(tree, logger); + } + } + if (!disableDiagnosticValidation) { outCompilation.GetDiagnostics().AssertMaxSeverity(DiagnosticSeverity.Info); @@ -831,6 +848,59 @@ internal static void AssertMaxSeverity(this IEnumerable diagnostics, { Assert.DoesNotContain(diagnostics, diagnostic => diagnostic.Severity > maxSeverity); } + + private static void LogGeneratedCode(SyntaxTree tree, ITestOutputHelper logger) + { + logger.WriteLine(FileSeparator); + logger.WriteLine($"{tree.FilePath} content:"); + logger.WriteLine(FileSeparator); + using NumberedSourceFileWriter lineWriter = new(logger); + tree.GetRoot().WriteTo(lineWriter); + lineWriter.WriteLine(string.Empty); + } + + private static readonly string FileSeparator = new string('=', 140); + + private sealed class NumberedSourceFileWriter : TextWriter + { + private readonly ITestOutputHelper _logger; + private readonly StringBuilder _lineBuilder = new StringBuilder(); + private int _lineNumber; + + internal NumberedSourceFileWriter(ITestOutputHelper logger) + { + _logger = logger; + } + + public override Encoding Encoding => Encoding.Unicode; + + public override void WriteLine(string? value) + { + _logger.WriteLine($"{++_lineNumber,6}: {_lineBuilder}{value}"); + _lineBuilder.Clear(); + } + + public override void Write(string? value) + { + if (value is null) + { + return; + } + + if (value.EndsWith("\r\n", StringComparison.Ordinal)) + { + WriteLine(value.Substring(0, value.Length - 2)); + } + else if (value.EndsWith("\n", StringComparison.Ordinal)) + { + WriteLine(value.Substring(0, value.Length - 1)); + } + else + { + _lineBuilder.Append(value); + } + } + } } public record struct DiagnosticData( diff --git a/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs b/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs index 185881ccbcd..9faf0472700 100644 --- a/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs +++ b/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs @@ -5,6 +5,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Xunit; +using Xunit.Abstractions; namespace System.Text.Json.SourceGeneration.UnitTests { @@ -12,7 +13,7 @@ namespace System.Text.Json.SourceGeneration.UnitTests [SkipOnCoreClr("https://github.com/dotnet/runtime/issues/71962", ~RuntimeConfiguration.Release)] [SkipOnMono("https://github.com/dotnet/runtime/issues/92467")] [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotX86Process))] // https://github.com/dotnet/runtime/issues/71962 - public class GeneratorTests + public class GeneratorTests(ITestOutputHelper logger) { [Fact] public void TypeDiscoveryPrimitivePOCO() @@ -54,7 +55,7 @@ public void UsePrivates() """; Compilation compilation = CompilationHelper.CreateCompilation(source); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); Assert.Equal(5, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.MyType"); @@ -109,7 +110,7 @@ public void UsePrivates() Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); Assert.Equal(6, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.MyType"); @@ -169,7 +170,7 @@ public void UsePrivates() Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); Assert.Equal(6, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.MyType"); @@ -271,7 +272,7 @@ public class WeatherForecastWithPOCOs MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) }; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - CompilationHelper.RunJsonSourceGenerator(compilation); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); } [Fact] @@ -312,7 +313,7 @@ public void UsePrivates() Compilation compilation = CompilationHelper.CreateCompilation(source); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); Assert.Equal(5, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::MyType"); @@ -362,7 +363,7 @@ public record AppRecord(int Id) Compilation compilation = CompilationHelper.CreateCompilation(source); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); Assert.Equal(3, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.AppRecord"); @@ -396,7 +397,7 @@ internal partial class JsonContext : JsonSerializerContext MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) }; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); Assert.Equal(3, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::ReferencedAssembly.LibRecord"); @@ -435,7 +436,7 @@ internal record AppRecord : LibRecord Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); Assert.Equal(3, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.AppRecord"); @@ -486,7 +487,7 @@ public class MyType MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) }; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); // Should find the generated type. Assert.Equal(2, result.AllGeneratedTypes.Count()); @@ -495,7 +496,7 @@ public class MyType } [Fact] - public static void NoWarningsDueToObsoleteMembers() + public void NoWarningsDueToObsoleteMembers() { string source = """ using System; @@ -518,11 +519,11 @@ public class ClassWithObsolete """; Compilation compilation = CompilationHelper.CreateCompilation(source); - CompilationHelper.RunJsonSourceGenerator(compilation); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); } [Fact] - public static void NoErrorsWhenUsingReservedCSharpKeywords() + public void NoErrorsWhenUsingReservedCSharpKeywords() { string source = """ using System.Text.Json.Serialization; @@ -541,7 +542,7 @@ public class ClassWithPropertiesAndFieldsThatAreReservedKeywords """; Compilation compilation = CompilationHelper.CreateCompilation(source); - CompilationHelper.RunJsonSourceGenerator(compilation); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); } [Fact] @@ -564,7 +565,7 @@ internal partial class JsonContext : JsonSerializerContext Compilation compilation = CompilationHelper.CreateCompilation(source); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); // Should find the generated type. Assert.Equal(3, result.AllGeneratedTypes.Count()); @@ -574,7 +575,7 @@ internal partial class JsonContext : JsonSerializerContext } [Fact] - public static void NoErrorsWhenUsingTypesWithMultipleEqualsOperators() + public void NoErrorsWhenUsingTypesWithMultipleEqualsOperators() { // Regression test for https://github.com/dotnet/runtime/issues/103515 string source = """ @@ -604,11 +605,11 @@ internal partial class JsonSourceGenerationContext : JsonSerializerContext """; Compilation compilation = CompilationHelper.CreateCompilation(source); - CompilationHelper.RunJsonSourceGenerator(compilation); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); } [Fact] - public static void NoErrorsWhenUsingIgnoredReservedCSharpKeywords() + public void NoErrorsWhenUsingIgnoredReservedCSharpKeywords() { string source = """ using System.Text.Json.Serialization; @@ -627,7 +628,7 @@ public class ClassWithPropertyNameThatIsAReservedKeyword """; Compilation compilation = CompilationHelper.CreateCompilation(source); - CompilationHelper.RunJsonSourceGenerator(compilation); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); } [Fact] @@ -678,7 +679,7 @@ public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSeri Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); Assert.Equal(3, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::Test.Sample"); @@ -724,7 +725,7 @@ public class NestedGenericClass Compilation compilation = CompilationHelper.CreateCompilation(source); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); Assert.Equal(5, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::System.Collections.Generic.Dictionary"); @@ -771,7 +772,7 @@ public class MyClass """; Compilation compilation = CompilationHelper.CreateCompilation(source, parseOptions: CompilationHelper.CreateParseOptions(languageVersion)); - CompilationHelper.RunJsonSourceGenerator(compilation); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); } [Fact] @@ -802,7 +803,7 @@ internal partial class JsonContext : JsonSerializerContext """; Compilation compilation = CompilationHelper.CreateCompilation(source); - CompilationHelper.RunJsonSourceGenerator(compilation); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); } #if ROSLYN4_4_OR_GREATER && NET @@ -828,7 +829,7 @@ public partial class MyContext : JsonSerializerContext """; Compilation compilation = CompilationHelper.CreateCompilation(source, parseOptions: CompilationHelper.CreateParseOptions(LanguageVersion.CSharp11)); - CompilationHelper.RunJsonSourceGenerator(compilation); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); } #endif @@ -856,7 +857,7 @@ internal partial class ModelContext : JsonSerializerContext """; Compilation compilation = CompilationHelper.CreateCompilation(source); - CompilationHelper.RunJsonSourceGenerator(compilation); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); } [Fact] @@ -881,7 +882,88 @@ public partial class MyContext : JsonSerializerContext """; Compilation compilation = CompilationHelper.CreateCompilation(source); - CompilationHelper.RunJsonSourceGenerator(compilation); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); } + +#if ROSLYN4_4_OR_GREATER && NET + [Fact] + public void PropertyWithExperimentalType_JsonIgnore_CompilesSuccessfully() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + using System.Text.Json.Serialization; + + [Experimental("EXP001")] + public class ExperimentalType + { + public int Value { get; set; } + } + + public class MyPoco + { + [JsonIgnore] + #pragma warning disable EXP001 + public ExperimentalType ExpType { get; set; } + #pragma warning restore EXP001 + } + + [JsonSerializable(typeof(MyPoco))] + public partial class MyContext : JsonSerializerContext + { + } + """; + + Compilation compilation = CompilationHelper.CreateCompilation(source); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); + } + + [Fact] + public void PocoWithExperimentalProperty_JsonIgnore_CompilesSuccessfully() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + using System.Text.Json.Serialization; + + public class MyPoco + { + [Experimental("EXP001"), JsonIgnore] + public int ExperimentalProperty { get; set; } + } + + [JsonSerializable(typeof(MyPoco))] + public partial class MyContext : JsonSerializerContext + { + } + """; + + Compilation compilation = CompilationHelper.CreateCompilation(source); + CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger); + } + + [Fact] + public void PocoWithExperimentalProperty_NoJsonIgnore_EmitsDiagnostic() + { + string source = """ + using System.Diagnostics.CodeAnalysis; + using System.Text.Json.Serialization; + + public class MyPoco + { + [Experimental("EXP001")] + public int ExperimentalProperty { get; set; } + } + + [JsonSerializable(typeof(MyPoco))] + public partial class MyContext : JsonSerializerContext + { + } + """; + + Compilation compilation = CompilationHelper.CreateCompilation(source); + var result = CompilationHelper.RunJsonSourceGenerator(compilation, logger: logger, disableDiagnosticValidation: true); + + Assert.NotEmpty(result.NewCompilation.GetDiagnostics().Where(d => d.Id == "EXP001")); + } +#endif } } diff --git a/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Roslyn4.4.Unit.Tests.csproj b/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Roslyn4.4.Unit.Tests.csproj index 7886da32200..b453e5051e1 100644 --- a/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Roslyn4.4.Unit.Tests.csproj +++ b/src/runtime/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Roslyn4.4.Unit.Tests.csproj @@ -1,6 +1,6 @@ - $(MicrosoftCodeAnalysisVersion_4_4) + $(MicrosoftCodeAnalysisVersion_4_8) $(DefineConstants);ROSLYN4_0_OR_GREATER;ROSLYN4_4_OR_GREATER true diff --git a/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_120414/Runtime_120414.cs b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_120414/Runtime_120414.cs new file mode 100644 index 00000000000..f590d9fee53 --- /dev/null +++ b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_120414/Runtime_120414.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Numerics; +using System.Runtime.Intrinsics; +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_120414 +{ + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector128 DuplicateFromVec2(Vector2 s) => + Vector128.Create(Unsafe.As(ref s)).AsSingle(); + + [Fact] + public static void TestEntryPoint() + { + Vector2 testVec = new Vector2(1.0f, 0.5f); + Vector128 result = DuplicateFromVec2(testVec); + Assert.Equal(1.0f, result[0]); + Assert.Equal(0.5f, result[1]); + Assert.Equal(1.0f, result[2]); + Assert.Equal(0.5f, result[3]); + } +} diff --git a/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_120414/Runtime_120414.csproj b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_120414/Runtime_120414.csproj new file mode 100644 index 00000000000..501217e4d86 --- /dev/null +++ b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_120414/Runtime_120414.csproj @@ -0,0 +1,9 @@ + + + None + True + + + + + diff --git a/src/runtime/src/tests/profiler/unittest/moduleload.cs b/src/runtime/src/tests/profiler/unittest/moduleload.cs index 17e1312d8b0..4539597aea5 100644 --- a/src/runtime/src/tests/profiler/unittest/moduleload.cs +++ b/src/runtime/src/tests/profiler/unittest/moduleload.cs @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.Loader; namespace Profiler.Tests { @@ -21,13 +23,25 @@ public static int RunTest(string[] args) .DefineDynamicModule("TestModule") .DefineType("TestClass", TypeAttributes.Public) .CreateType(); - + var obj = Activator.CreateInstance(type); if (obj == null) { throw new NullReferenceException(); } + // Trigger module load in multiple threads + int threadCount = 20; + List threads = new(threadCount); + for (int i = 0; i < threadCount; i++) + threads.Add(new Thread(() => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName("unloadlibrary")))); + + foreach (var thread in threads) + thread.Start(); + + foreach (var thread in threads) + thread.Join(); + return 100; } diff --git a/src/runtime/src/tests/profiler/unittest/moduleload.csproj b/src/runtime/src/tests/profiler/unittest/moduleload.csproj index e94b734bb5a..83770db0d9b 100644 --- a/src/runtime/src/tests/profiler/unittest/moduleload.csproj +++ b/src/runtime/src/tests/profiler/unittest/moduleload.csproj @@ -15,6 +15,7 @@ + diff --git a/src/source-manifest.json b/src/source-manifest.json index 76ca812877f..b5ba0683c6c 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -79,10 +79,10 @@ "commitSha": "929ae2333a73eca047b9b6e2f01bf7121558308f" }, { - "barId": 286526, + "barId": 286595, "path": "runtime", "remoteUri": "https://github.com/dotnet/runtime", - "commitSha": "647691bc0fe3113ad72643efed1597676b525c55" + "commitSha": "a402595199e366ae6cf697d74b9dd43081fa2fcd" }, { "barId": 277711, From 0b60d265d30d96c827b73dbce74cb78f600d3c92 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 12 Oct 2025 09:50:08 -0700 Subject: [PATCH 28/28] [release/10.0.1xx] Source code updates from dotnet/diagnostics (#2847) Co-authored-by: dotnet-maestro[bot] --- .../.github/ISSUE_TEMPLATE/01_Bug_Report.md | 2 +- .../src/SOS/SOS.Package/SOS.Package.csproj | 81 ++++++++++--------- src/source-manifest.json | 4 +- 3 files changed, 47 insertions(+), 40 deletions(-) diff --git a/src/diagnostics/.github/ISSUE_TEMPLATE/01_Bug_Report.md b/src/diagnostics/.github/ISSUE_TEMPLATE/01_Bug_Report.md index 918b30c8c8d..d643b2347d8 100644 --- a/src/diagnostics/.github/ISSUE_TEMPLATE/01_Bug_Report.md +++ b/src/diagnostics/.github/ISSUE_TEMPLATE/01_Bug_Report.md @@ -26,7 +26,7 @@ assignees: '' * Do you know whether it is specific to that configuration? * Are you running in any particular type of environment? (e.g. Containers, a cloud scenario, app you are trying to target is a different user) * Is it a self-contained published application? -* What's the output of `dotnet info` +* What's the output of `dotnet --info` --> ### Regression? diff --git a/src/diagnostics/src/SOS/SOS.Package/SOS.Package.csproj b/src/diagnostics/src/SOS/SOS.Package/SOS.Package.csproj index ed219206423..5607b1c05fe 100644 --- a/src/diagnostics/src/SOS/SOS.Package/SOS.Package.csproj +++ b/src/diagnostics/src/SOS/SOS.Package/SOS.Package.csproj @@ -14,7 +14,7 @@ true false - + @@ -30,47 +30,54 @@ - + - SOS - $(FileVersion) - Debugging aid for .NET Core programs and runtimes - - - - - - - - - - - - - - - - - - - - - - - - - - !soshelp - Displays all available SOS commands or details about the command - - - - - + SOS + $(FileVersion) + Debugging aid for .NET Core programs and runtimes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + !soshelp + Displays all available SOS commands or details about the command + + + + + ]]> diff --git a/src/source-manifest.json b/src/source-manifest.json index b5ba0683c6c..1872b9fca63 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -31,10 +31,10 @@ "commitSha": "c0c52874069a4dc0fe1e880014e6a5f316e9d3b8" }, { - "barId": 285923, + "barId": 286647, "path": "diagnostics", "remoteUri": "https://github.com/dotnet/diagnostics", - "commitSha": "f40e210b5da69e3c7585917137322cac01f0dffc" + "commitSha": "53c7e6f445c2d1a918707a609b0fd08c3604c659" }, { "barId": 286575,