diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml
index e740ad8c75f5..806e13e53edc 100644
--- a/.github/policies/resourceManagement.yml
+++ b/.github/policies/resourceManagement.yml
@@ -1,10 +1,10 @@
-id:
+id:
name: GitOps.PullRequestIssueManagement
description: GitOps.PullRequestIssueManagement primitive
-owner:
+owner:
resource: repository
disabled: false
-where:
+where:
configuration:
resourceManagementConfiguration:
scheduledSearches:
@@ -90,7 +90,7 @@ configuration:
label: needs-breaking-change-doc-created
- addReply:
reply: >-
- Added `needs-breaking-change-doc-created` label because this PR has the `breaking-change` label.
+ Added `needs-breaking-change-doc-created` label because this PR has the `breaking-change` label.
When you commit this breaking change:
@@ -103,5 +103,23 @@ configuration:
You can refer to the [.NET SDK breaking change guidelines](https://github.com/dotnet/sdk/blob/main/documentation/project-docs/breaking-change-guidelines.md)
description: Add breaking change instructions to PR.
-onFailure:
-onSuccess:
+ - description: Remind Telemetry PR authors of the telemetry guidelines
+ if:
+ - payloadType: Pull_Request
+ - labelAdded:
+ label: Area-Telemetry
+ then:
+ - addReply:
+ reply: >-
+ This PR has been labeled with `Area-Telemetry`. Please ensure that any telemetry changes in this PR
+
+ * comply with the [published guidance](https://learn.microsoft.com/dotnet/core/tools/telemetry#data-points)
+ * are added to the [repo-local telemetry documentation](./documentation/project-docs/telemetry.md)
+ * get a matching .NET Docs issue raised to document the telemetry changes
+ * Go to https://learn.microsoft.com/dotnet/core/tools/telemetry
+ * Scroll down to the bottom and click the 'Open a documentation issue' link to create an issue with pre-filled details
+ - requestReview:
+ reviewer: dsplaisted
+
+onFailure:
+onSuccess:
diff --git a/.vsts-ci.yml b/.vsts-ci.yml
index 429eaf993572..d63b77913b8a 100644
--- a/.vsts-ci.yml
+++ b/.vsts-ci.yml
@@ -98,10 +98,11 @@ extends:
name: $(DncEngInternalBuildPool)
image: windows.vs2022.amd64
os: windows
- helixTargetQueue: windows.amd64.vs2022.pre
+ helixTargetQueue: windows.amd64.vs2026.pre.scout
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/.vsts-pr.yml b/.vsts-pr.yml
index a0ce56e66843..26dc80c5a611 100644
--- a/.vsts-pr.yml
+++ b/.vsts-pr.yml
@@ -42,7 +42,7 @@ stages:
name: $(DncEngPublicBuildPool)
demands: ImageOverride -equals windows.vs2022.amd64.open
os: windows
- helixTargetQueue: windows.amd64.vs2022.pre.open
+ helixTargetQueue: windows.amd64.vs2026.pre.scout.open
############### LINUX ###############
- template: /eng/pipelines/templates/jobs/sdk-job-matrix.yml
diff --git a/CODEOWNERS b/CODEOWNERS
index a7e47c14ebd5..4591eb1ff8d7 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -31,8 +31,8 @@
/src/WasmSdk @lewing @akoeplinger @pavelsavara @maraf
# Area-Format
-/src/Cli/dotnet/commands/dotnet-format @arunchndr
-/test/dotnet-format.UnitTests @arunchndr
+/src/Cli/dotnet/commands/dotnet-format @phil-allen-msft
+/test/dotnet-format.UnitTests @phil-allen-msft
# Area-NuGet
/src/Cli/dotnet/Commands/NuGet @dotnet/nuget-team
@@ -77,10 +77,10 @@
/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.ClickOnce.targets @sujitnayak
# Area-Watch
-/test/TestAssets/TestProjects/Watch*/ @tmat @arunchndr @dotnet/roslyn-ide
-/test/dotnet-watch.Tests/ @tmat @arunchndr @dotnet/roslyn-ide
+/test/TestAssets/TestProjects/Watch*/ @tmat @dotnet/roslyn-ide
+/test/dotnet-watch.Tests/ @tmat @dotnet/roslyn-ide
/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ @dotnet/aspnet-blazor-eng
-/src/BuiltInTools/* @tmat @arunchndr @dotnet/roslyn-ide
+/src/BuiltInTools/* @tmat @dotnet/roslyn-ide
/src/BuiltInTools/BrowserRefresh @dotnet/aspnet-blazor-eng
/src/BuiltInTools/AspireService @dotnet/aspnet-blazor-eng
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 788923bf48d6..ecc47ba3f164 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -5,10 +5,11 @@
$(NoWarn);NU1507
-
+
+
@@ -93,7 +94,7 @@
-
+
@@ -101,6 +102,7 @@
+
diff --git a/build/RunTestTemplateTests.ps1 b/build/RunTestTemplateTests.ps1
deleted file mode 100644
index 5fe903b77f34..000000000000
--- a/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/documentation/general/analyzer-redirecting.md b/documentation/general/analyzer-redirecting.md
index 208c28734787..e999b98d76fe 100644
--- a/documentation/general/analyzer-redirecting.md
+++ b/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/documentation/general/dotnet-run-file.md b/documentation/general/dotnet-run-file.md
index 8111a435800f..41bb96b5f6a2 100644
--- a/documentation/general/dotnet-run-file.md
+++ b/documentation/general/dotnet-run-file.md
@@ -32,6 +32,8 @@ Additionally, the implicit project file has the following customizations:
- `PublishAot` is set to `true`, see [`dotnet publish file.cs`](#other-commands) for more details.
+- `UserSecretsId` is set to a hash of the entry point file path.
+
- [File-level directives](#directives-for-project-metadata) are applied.
- The following are virtual only, i.e., not preserved after [converting to a project](#grow-up):
@@ -287,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.
@@ -295,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/documentation/manpages/sdk/dotnet-build.1 b/documentation/manpages/sdk/dotnet-build.1
index 99fe1e657990..fb7ce5950153 100644
--- a/documentation/manpages/sdk/dotnet-build.1
+++ b/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/documentation/manpages/sdk/dotnet-clean.1 b/documentation/manpages/sdk/dotnet-clean.1
index a259f0fe2df5..d59683069976 100644
--- a/documentation/manpages/sdk/dotnet-clean.1
+++ b/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/documentation/manpages/sdk/dotnet-pack.1 b/documentation/manpages/sdk/dotnet-pack.1
index 729fa6810b4c..58e02e3e5683 100644
--- a/documentation/manpages/sdk/dotnet-pack.1
+++ b/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/documentation/manpages/sdk/dotnet-publish.1 b/documentation/manpages/sdk/dotnet-publish.1
index 64610ed45272..77da5ae6f4be 100644
--- a/documentation/manpages/sdk/dotnet-publish.1
+++ b/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/documentation/manpages/sdk/dotnet-restore.1 b/documentation/manpages/sdk/dotnet-restore.1
index 498f0b210e84..334fba4e4b17 100644
--- a/documentation/manpages/sdk/dotnet-restore.1
+++ b/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/documentation/manpages/sdk/dotnet-run.1 b/documentation/manpages/sdk/dotnet-run.1
index 65cf2e8d10a8..c37a294d9f89 100644
--- a/documentation/manpages/sdk/dotnet-run.1
+++ b/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/documentation/manpages/sdk/dotnet-watch.1 b/documentation/manpages/sdk/dotnet-watch.1
index 6a02e55593a9..538a5acd0632 100644
--- a/documentation/manpages/sdk/dotnet-watch.1
+++ b/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/documentation/project-docs/telemetry.md b/documentation/project-docs/telemetry.md
new file mode 100644
index 000000000000..e559f60bb25b
--- /dev/null
+++ b/documentation/project-docs/telemetry.md
@@ -0,0 +1,318 @@
+# .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)
+ - [Common Properties Collected](#common-properties-collected)
+ - [Telemetry Events](#telemetry-events)
+ - [Core CLI Events](#core-cli-events)
+ - [Template Engine Events](#template-engine-events)
+ - [SDK-Collected Build Events](#sdk-collected-build-events)
+ - [MSBuild Engine Telemetry](#msbuild-engine-telemetry)
+ - [Container Events](#container-events)
+ - [`dotnet new` Command MSBuild Evaluation](#dotnet-new-command-msbuild-evaluation)
+ - [How to update this document](#how-to-update-this-document)
+
+## How to Control Telemetry
+
+### Disabling Telemetry
+
+The .NET SDK telemetry can be disabled using the following environment variable:
+
+- **`DOTNET_CLI_TELEMETRY_OPTOUT`**: Set to `1`, `true`, or `yes` to opt-out of telemetry collection
+ - Example: `export DOTNET_CLI_TELEMETRY_OPTOUT=1` (Linux/macOS)
+ - 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
+ - Values: `true`, `1`, or `yes` to mute messages
+ - Values: `false`, `0`, or `no` to allow messages
+ - Default: `false` (messages are displayed)
+ - Note: This flag does not affect telemetry collection itself
+
+### Telemetry Configuration
+
+- **Default Behavior**:
+ - 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)
+
+- **Event Namespace**: All telemetry events are automatically prefixed with `dotnet/cli/`
+
+## Common Properties Collected
+
+Every telemetry event automatically includes these common properties:
+
+| Property | Description | Example Value |
+|----------|-------------|---------------|
+| **OS Version** | Operating system version | `Microsoft Windows 10.0.14393` |
+| **OS Platform** | Operating system platform | `Windows`, `Linux`, `OSX` |
+| **OS Architecture** | Operating system architecture | `X64`, `X86`, `Arm64` |
+| **Output Redirected** | Whether console output is redirected | `True` or `False` |
+| **Runtime Id** | .NET runtime identifier | `win10-x64`, `linux-x64` |
+| **Product Version** | .NET SDK version | `8.0.100` |
+| **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 |
+| **Device ID** | Device identifier | Device-specific ID |
+| **Kernel Version** | OS kernel version | `Darwin 17.4.0`, `Linux 4.9.0` |
+| **Installation Type** | How the SDK was installed | Installation method |
+| **Product Type** | Type of .NET product | Product identifier |
+| **Libc Release** | Libc release information | Libc release version |
+| **Libc Version** | Libc version information | Libc version number |
+| **SessionId** | Unique session identifier | GUID |
+
+## Telemetry Events
+
+### 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
+
+---
+
+#### `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
+
+---
+
+#### `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.)
+
+**Description**: Tracks usage patterns of main dotnet commands
+
+---
+
+#### `sublevelparser/command`
+
+**When fired**: For subcommands and specific command options
+
+**Properties**: Various depending on command (verbosity, configuration, framework, etc.)
+
+**Description**: Tracks detailed command option usage
+
+---
+
+#### `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
+
+**Description**: Tracks how commands are resolved in the CLI
+
+---
+
+#### `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
+
+---
+
+#### `mainCatchException/exception`
+
+**When fired**: When unhandled exceptions occur in the main CLI
+
+**Properties**:
+
+- `exceptionType`: Type of exception
+- `detail`: Exception details (sensitive message removed)
+
+**Description**: Tracks unhandled exceptions for diagnostics
+
+### 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
+
+---
+
+#### `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)
+- `template-name`: SHA256 hash of template identity
+- `template-short-name`: SHA256 hash of template short names
+- `package-name`: SHA256 hash of package name
+- `package-version`: SHA256 hash of package version
+- `is-template-3rd-party`: Whether template is third-party
+- `create-success`: Whether creation succeeded
+- `auth`: Authentication choice (only sent for Microsoft-authored templates)
+
+**Description**: Tracks template usage and creation success
+
+### 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
+- `UseApphost`: Whether using app host
+- `OutputType`: Output type (Exe, Library, etc.)
+- `UseArtifactsOutput`: Whether using artifacts output
+- `ArtifactsPathLocationType`: Artifacts path location type - one of `Explicitly Specified`, `DirectoryBuildPropsFolder`, or `ProjectFolder`.
+
+**Description**: Tracks target framework configurations
+
+---
+
+#### `taskBaseCatchException`
+
+**When fired**: When exceptions occur in SDK-provided MSBuild tasks
+
+**Properties**:
+
+- `exceptionType`: Exception type
+- `detail`: Exception details (message removed)
+
+**Description**: Tracks exceptions in MSBuild task execution
+
+---
+
+#### `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
+
+**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
+
+**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()
+
+**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.
+
+### Container Events
+
+See [Container Telemetry Documentation](https://github.com/dotnet/sdk-container-builds/blob/main/docs/Telemetry.md) for details.
+
+### `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
+
+**Description**: Tracks MSBuild evaluation performance for new projects
+
+## 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
diff --git a/eng/Signing.props b/eng/Signing.props
index 484697efecbc..872602d12f5c 100644
--- a/eng/Signing.props
+++ b/eng/Signing.props
@@ -84,6 +84,9 @@
+
+
+
diff --git a/eng/Version.Details.props b/eng/Version.Details.props
index 91a79483b9b9..01d2dc185123 100644
--- a/eng/Version.Details.props
+++ b/eng/Version.Details.props
@@ -1,3 +1,4 @@
+
2.1.0
+
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.256
+ 7.0.0-preview.2.2562.1.0-preview.25551.14.1.0-preview.25551.1
@@ -173,7 +175,6 @@ This file should be imported by eng/Versions.props
$(MicrosoftBclAsyncInterfacesPackageVersion)$(MicrosoftBuildPackageVersion)$(MicrosoftBuildLocalizationPackageVersion)
- $(MicrosoftBuildNuGetSdkResolverPackageVersion)$(MicrosoftBuildTasksGitPackageVersion)$(MicrosoftCodeAnalysisPackageVersion)$(MicrosoftCodeAnalysisBuildClientPackageVersion)
@@ -239,22 +240,6 @@ This file should be imported by eng/Versions.props
$(MicrosoftWin32SystemEventsPackageVersion)$(MicrosoftWindowsDesktopAppInternalPackageVersion)$(MicrosoftWindowsDesktopAppRefPackageVersion)
- $(NuGetBuildTasksPackageVersion)
- $(NuGetBuildTasksConsolePackageVersion)
- $(NuGetBuildTasksPackPackageVersion)
- $(NuGetCommandLineXPlatPackageVersion)
- $(NuGetCommandsPackageVersion)
- $(NuGetCommonPackageVersion)
- $(NuGetConfigurationPackageVersion)
- $(NuGetCredentialsPackageVersion)
- $(NuGetDependencyResolverCorePackageVersion)
- $(NuGetFrameworksPackageVersion)
- $(NuGetLibraryModelPackageVersion)
- $(NuGetLocalizationPackageVersion)
- $(NuGetPackagingPackageVersion)
- $(NuGetProjectModelPackageVersion)
- $(NuGetProtocolPackageVersion)
- $(NuGetVersioningPackageVersion)$(SystemCodeDomPackageVersion)$(SystemCommandLinePackageVersion)$(SystemComponentModelCompositionPackageVersion)
@@ -279,6 +264,24 @@ This file should be imported by eng/Versions.props
$(SystemWindowsExtensionsPackageVersion)$(NETStandardLibraryRefPackageVersion)
+
+ $(MicrosoftBuildNuGetSdkResolverPackageVersion)
+ $(NuGetBuildTasksPackageVersion)
+ $(NuGetBuildTasksConsolePackageVersion)
+ $(NuGetBuildTasksPackPackageVersion)
+ $(NuGetCommandLineXPlatPackageVersion)
+ $(NuGetCommandsPackageVersion)
+ $(NuGetCommonPackageVersion)
+ $(NuGetConfigurationPackageVersion)
+ $(NuGetCredentialsPackageVersion)
+ $(NuGetDependencyResolverCorePackageVersion)
+ $(NuGetFrameworksPackageVersion)
+ $(NuGetLibraryModelPackageVersion)
+ $(NuGetLocalizationPackageVersion)
+ $(NuGetPackagingPackageVersion)
+ $(NuGetProjectModelPackageVersion)
+ $(NuGetProtocolPackageVersion)
+ $(NuGetVersioningPackageVersion)$(MicrosoftTestingPlatformPackageVersion)$(MSTestPackageVersion)
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 2f4d96261324..516c4906c84f 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -124,74 +124,74 @@
https://github.com/dotnet/dotnetbe28ec777bf12db631725399c442448d52093087
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145
-
- https://github.com/dotnet/dotnet
- be28ec777bf12db631725399c442448d52093087
+
+ https://github.com/nuget/nuget.client
+ 97c64b5dfcc39b3babf6b3dfa828aa737860c145https://github.com/dotnet/dotnet
diff --git a/eng/Versions.props b/eng/Versions.props
index 968b8a18201c..d60cd6039953 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -6,7 +6,7 @@
100
- 1
+ 200
- rc
+ previewrtmservicing
- 2
+ 0
@@ -38,8 +38,8 @@
3620
- 18
- 7
+ 19
+ 8
<_NET70ILLinkPackVersion>7.0.100-1.23211.1
diff --git a/eng/dotnet-format/dotnet-format-integration.yml b/eng/dotnet-format/dotnet-format-integration.yml
index 1fa8bbb8ad9f..25c17948bf59 100644
--- a/eng/dotnet-format/dotnet-format-integration.yml
+++ b/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/eng/pipelines/templates/jobs/sdk-build.yml b/eng/pipelines/templates/jobs/sdk-build.yml
index c1ec3d7dfcd1..a9fc3537bfcb 100644
--- a/eng/pipelines/templates/jobs/sdk-build.yml
+++ b/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,9 +107,6 @@ jobs:
BuildConfig: $(buildConfiguration)
TestFullMSBuild: ${{ parameters.testFullMSBuild }}
- - powershell: build/RunTestTemplateTests.ps1
- displayName: 🟣 Run Test Templates Tests
-
- ${{ else }}:
- script: |
source $(Build.SourcesDirectory)/eng/common/native/init-os-and-arch.sh
@@ -140,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 }}
@@ -158,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: @
@@ -166,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/eng/pipelines/templates/jobs/sdk-job-matrix.yml b/eng/pipelines/templates/jobs/sdk-job-matrix.yml
index 8e9000f3c6cc..870f20d8f88b 100644
--- a/eng/pipelines/templates/jobs/sdk-job-matrix.yml
+++ b/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/global.json b/global.json
index 6e18af32ed70..3d11cb5599a3 100644
--- a/global.json
+++ b/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)"
diff --git a/sdk.slnx b/sdk.slnx
index 0246a040f447..dc0633c42d02 100644
--- a/sdk.slnx
+++ b/sdk.slnx
@@ -312,6 +312,7 @@
+
diff --git a/src/BuiltInTools/AspireService/AspireServerService.cs b/src/BuiltInTools/AspireService/AspireServerService.cs
index bf2f8f341b81..064de0ee7a50 100644
--- a/src/BuiltInTools/AspireService/AspireServerService.cs
+++ b/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/BuiltInTools/AspireService/Microsoft.WebTools.AspireService.Package.csproj b/src/BuiltInTools/AspireService/Microsoft.WebTools.AspireService.Package.csproj
index 952651e23062..2c32befe16b6 100644
--- a/src/BuiltInTools/AspireService/Microsoft.WebTools.AspireService.Package.csproj
+++ b/src/BuiltInTools/AspireService/Microsoft.WebTools.AspireService.Package.csproj
@@ -9,6 +9,7 @@
true
+ truetrueAspire.Tools.Servicefalse
diff --git a/src/BuiltInTools/AspireService/Models/SessionChangeNotification.cs b/src/BuiltInTools/AspireService/Models/SessionChangeNotification.cs
index 579fe6b4a88f..d4213593cf5a 100644
--- a/src/BuiltInTools/AspireService/Models/SessionChangeNotification.cs
+++ b/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/BuiltInTools/BrowserRefresh/Microsoft.AspNetCore.Watch.BrowserRefresh.csproj b/src/BuiltInTools/BrowserRefresh/Microsoft.AspNetCore.Watch.BrowserRefresh.csproj
index b56559840a89..84852c4df9a9 100644
--- a/src/BuiltInTools/BrowserRefresh/Microsoft.AspNetCore.Watch.BrowserRefresh.csproj
+++ b/src/BuiltInTools/BrowserRefresh/Microsoft.AspNetCore.Watch.BrowserRefresh.csproj
@@ -7,7 +7,10 @@
net6.0MicrosoftAspNetCore
+
true
+ true
+ trueMicrosoft.DotNet.HotReload.Web.MiddlewarePackage containing Hot Reload middleware.true
diff --git a/src/BuiltInTools/DotNetDeltaApplier/Microsoft.Extensions.DotNetDeltaApplier.csproj b/src/BuiltInTools/DotNetDeltaApplier/Microsoft.Extensions.DotNetDeltaApplier.csproj
index d5c6f3848416..5172480c5f98 100644
--- a/src/BuiltInTools/DotNetDeltaApplier/Microsoft.Extensions.DotNetDeltaApplier.csproj
+++ b/src/BuiltInTools/DotNetDeltaApplier/Microsoft.Extensions.DotNetDeltaApplier.csproj
@@ -16,6 +16,8 @@
true
+ true
+ trueMicrosoft.DotNet.HotReload.Agent.HostPackage containing Hot Reload agent host.true
diff --git a/src/BuiltInTools/DotNetDeltaApplier/PipeListener.cs b/src/BuiltInTools/DotNetDeltaApplier/PipeListener.cs
index d596594e551d..6110f0fa631c 100644
--- a/src/BuiltInTools/DotNetDeltaApplier/PipeListener.cs
+++ b/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/BuiltInTools/DotNetDeltaApplier/StartupHook.cs b/src/BuiltInTools/DotNetDeltaApplier/StartupHook.cs
index f9ac8e3463f9..03c7b04a4fea 100644
--- a/src/BuiltInTools/DotNetDeltaApplier/StartupHook.cs
+++ b/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);
@@ -89,7 +124,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/BuiltInTools/HotReloadAgent.Data/Microsoft.DotNet.HotReload.Agent.Data.Package.csproj b/src/BuiltInTools/HotReloadAgent.Data/Microsoft.DotNet.HotReload.Agent.Data.Package.csproj
index 285d0de46e69..4dde206b752d 100644
--- a/src/BuiltInTools/HotReloadAgent.Data/Microsoft.DotNet.HotReload.Agent.Data.Package.csproj
+++ b/src/BuiltInTools/HotReloadAgent.Data/Microsoft.DotNet.HotReload.Agent.Data.Package.csproj
@@ -11,6 +11,7 @@
true
+ truetrueMicrosoft.DotNet.HotReload.Agent.Datafalse
diff --git a/src/BuiltInTools/HotReloadAgent.PipeRpc/Microsoft.DotNet.HotReload.Agent.PipeRpc.Package.csproj b/src/BuiltInTools/HotReloadAgent.PipeRpc/Microsoft.DotNet.HotReload.Agent.PipeRpc.Package.csproj
index a6a3b3ab0ad1..def624accfd0 100644
--- a/src/BuiltInTools/HotReloadAgent.PipeRpc/Microsoft.DotNet.HotReload.Agent.PipeRpc.Package.csproj
+++ b/src/BuiltInTools/HotReloadAgent.PipeRpc/Microsoft.DotNet.HotReload.Agent.PipeRpc.Package.csproj
@@ -11,6 +11,7 @@
true
+ truetrueMicrosoft.DotNet.HotReload.Agent.PipeRpcfalse
diff --git a/src/BuiltInTools/HotReloadAgent.PipeRpc/NamedPipeContract.cs b/src/BuiltInTools/HotReloadAgent.PipeRpc/NamedPipeContract.cs
index 66766e1c74e2..dfa0158c53cd 100644
--- a/src/BuiltInTools/HotReloadAgent.PipeRpc/NamedPipeContract.cs
+++ b/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/BuiltInTools/HotReloadAgent.WebAssembly.Browser/WebAssemblyHotReload.cs b/src/BuiltInTools/HotReloadAgent.WebAssembly.Browser/WebAssemblyHotReload.cs
index 2169ef3dbd9b..1aad8e47f072 100644
--- a/src/BuiltInTools/HotReloadAgent.WebAssembly.Browser/WebAssemblyHotReload.cs
+++ b/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/BuiltInTools/HotReloadAgent/HotReloadAgent.cs b/src/BuiltInTools/HotReloadAgent/HotReloadAgent.cs
index 4114bed5e6fd..f64180144078 100644
--- a/src/BuiltInTools/HotReloadAgent/HotReloadAgent.cs
+++ b/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/BuiltInTools/HotReloadAgent/MetadataUpdateHandlerInvoker.cs b/src/BuiltInTools/HotReloadAgent/MetadataUpdateHandlerInvoker.cs
index 952ba4866def..e841af26513e 100644
--- a/src/BuiltInTools/HotReloadAgent/MetadataUpdateHandlerInvoker.cs
+++ b/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/BuiltInTools/HotReloadAgent/Microsoft.DotNet.HotReload.Agent.Package.csproj b/src/BuiltInTools/HotReloadAgent/Microsoft.DotNet.HotReload.Agent.Package.csproj
index 67e670e57107..d44f61dd98ca 100644
--- a/src/BuiltInTools/HotReloadAgent/Microsoft.DotNet.HotReload.Agent.Package.csproj
+++ b/src/BuiltInTools/HotReloadAgent/Microsoft.DotNet.HotReload.Agent.Package.csproj
@@ -12,6 +12,7 @@
true
+ truetrueMicrosoft.DotNet.HotReload.Agentfalse
diff --git a/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs b/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs
index 7587b7623117..c7b325a4c348 100644
--- a/src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs
+++ b/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();
@@ -35,9 +38,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
@@ -70,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))]
@@ -101,8 +150,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 +200,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 +270,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 +295,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 +323,14 @@ async ValueTask WriteRequestAsync(CancellationToken cancellationToken)
private async ValueTask ReceiveUpdateResponseAsync(CancellationToken cancellationToken)
{
- // Should not be disposed:
+ var result = await _updateStatusSource.Task;
+ _updateStatusSource = new TaskCompletionSource();
+ return result;
+ }
+
+ private async ValueTask ReadUpdateResponseAsync(CancellationToken cancellationToken)
+ {
+ // Should be initialized:
Debug.Assert(_pipe != null);
var (success, log) = await UpdateResponse.ReadAsync(_pipe, cancellationToken);
@@ -296,10 +359,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/BuiltInTools/HotReloadClient/HotReloadClient.cs b/src/BuiltInTools/HotReloadClient/HotReloadClient.cs
index fe14176a8b6e..2a563419e4f2 100644
--- a/src/BuiltInTools/HotReloadClient/HotReloadClient.cs
+++ b/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;
@@ -41,25 +46,47 @@ 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();
+ 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
@@ -72,7 +99,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/BuiltInTools/dotnet-watch/HotReload/HotReloadClients.cs b/src/BuiltInTools/HotReloadClient/HotReloadClients.cs
similarity index 70%
rename from src/BuiltInTools/dotnet-watch/HotReload/HotReloadClients.cs
rename to src/BuiltInTools/HotReloadClient/HotReloadClients.cs
index b06fcc838485..fcf541045fc6 100644
--- a/src/BuiltInTools/dotnet-watch/HotReload/HotReloadClients.cs
+++ b/src/BuiltInTools/HotReloadClient/HotReloadClients.cs
@@ -1,20 +1,31 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+#nullable enable
+
+using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
-using Microsoft.Build.Graph;
-using Microsoft.DotNet.Watch;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace Microsoft.DotNet.HotReload;
-internal sealed class HotReloadClients(ImmutableArray<(HotReloadClient client, string name)> clients, BrowserRefreshServer? browserRefreshServer) : IDisposable
+internal sealed class HotReloadClients(ImmutableArray<(HotReloadClient client, string name)> clients, AbstractBrowserRefreshServer? browserRefreshServer) : IDisposable
{
- public HotReloadClients(HotReloadClient client, BrowserRefreshServer? browserRefreshServer)
+ public HotReloadClients(HotReloadClient client, AbstractBrowserRefreshServer? browserRefreshServer)
: this([(client, "")], browserRefreshServer)
{
}
+ ///
+ /// Disposes all clients. Can occur unexpectedly whenever the process exits.
+ ///
public void Dispose()
{
foreach (var (client, _) in clients)
@@ -23,9 +34,31 @@ public void Dispose()
}
}
- public BrowserRefreshServer? BrowserRefreshServer
+ 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.
///
@@ -48,6 +81,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)
@@ -56,11 +90,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, _)])
@@ -75,7 +111,9 @@ public async ValueTask> GetUpdateCapabilitiesAsync(Cancel
return [.. results.SelectMany(r => r).Distinct(StringComparer.Ordinal).OrderBy(c => c)];
}
- public async ValueTask ApplyManagedCodeUpdatesAsync(ImmutableArray updates, bool isProcessSuspended, CancellationToken cancellationToken)
+ /// Cancellation token. The cancellation should trigger on process terminatation.
+ /// 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;
@@ -120,9 +158,13 @@ public async ValueTask ApplyManagedCodeUpdatesAsync(ImmutableArrayCancellation token. The cancellation should trigger on process terminatation.
public async ValueTask InitialUpdatesAppliedAsync(CancellationToken cancellationToken)
{
if (clients is [var (singleClient, _)])
@@ -143,6 +186,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)
@@ -158,9 +202,14 @@ public async Task ApplyStaticAssetUpdatesAsync(IEnumerable<(string filePath, str
ImmutableArray content;
try
{
- content = ImmutableCollectionsMarshal.AsImmutableArray(await File.ReadAllBytesAsync(filePath, cancellationToken));
+#if NET
+ var blob = await File.ReadAllBytesAsync(filePath, cancellationToken);
+#else
+ var blob = File.ReadAllBytes(filePath);
+#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;
@@ -177,6 +226,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, _)])
@@ -189,6 +239,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/BuiltInTools/HotReloadClient/Logging/LogEvents.cs b/src/BuiltInTools/HotReloadClient/Logging/LogEvents.cs
index a74e5097a6d5..7be92781e01c 100644
--- a/src/BuiltInTools/HotReloadClient/Logging/LogEvents.cs
+++ b/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/BuiltInTools/HotReloadClient/Microsoft.DotNet.HotReload.Client.Package.csproj b/src/BuiltInTools/HotReloadClient/Microsoft.DotNet.HotReload.Client.Package.csproj
index 8dd5b87ac79b..7996da1c7dbe 100644
--- a/src/BuiltInTools/HotReloadClient/Microsoft.DotNet.HotReload.Client.Package.csproj
+++ b/src/BuiltInTools/HotReloadClient/Microsoft.DotNet.HotReload.Client.Package.csproj
@@ -13,6 +13,7 @@
true
+ truetrueMicrosoft.DotNet.HotReload.Clientfalse
diff --git a/src/BuiltInTools/HotReloadClient/Web/AbstractBrowserRefreshServer.cs b/src/BuiltInTools/HotReloadClient/Web/AbstractBrowserRefreshServer.cs
index eda15d200f96..91d99296db0b 100644
--- a/src/BuiltInTools/HotReloadClient/Web/AbstractBrowserRefreshServer.cs
+++ b/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/BuiltInTools/HotReloadClient/Web/BrowserConnection.cs b/src/BuiltInTools/HotReloadClient/Web/BrowserConnection.cs
index 507595eb89d1..498c26110089 100644
--- a/src/BuiltInTools/HotReloadClient/Web/BrowserConnection.cs
+++ b/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/BuiltInTools/dotnet-watch.slnf b/src/BuiltInTools/dotnet-watch.slnf
index 09d529c61e9c..b7454eb8869a 100644
--- a/src/BuiltInTools/dotnet-watch.slnf
+++ b/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/BuiltInTools/dotnet-watch/Aspire/AspireServiceFactory.cs b/src/BuiltInTools/dotnet-watch/Aspire/AspireServiceFactory.cs
index 1e84fb05a408..b7d669a89216 100644
--- a/src/BuiltInTools/dotnet-watch/Aspire/AspireServiceFactory.cs
+++ b/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();
// process termination should cancel output reader task:
await session.OutputReader;
diff --git a/src/BuiltInTools/dotnet-watch/Browser/BrowserLauncher.cs b/src/BuiltInTools/dotnet-watch/Browser/BrowserLauncher.cs
index 422cb1b8a774..c841191e0208 100644
--- a/src/BuiltInTools/dotnet-watch/Browser/BrowserLauncher.cs
+++ b/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 = [];
@@ -22,7 +23,7 @@ public void InstallBrowserLaunchTrigger(
ProcessSpec processSpec,
ProjectGraphNode projectNode,
ProjectOptions projectOptions,
- BrowserRefreshServer? server,
+ AbstractBrowserRefreshServer? server,
CancellationToken cancellationToken)
{
if (!CanLaunchBrowser(projectOptions, out var launchProfile))
@@ -59,20 +60,15 @@ public static string GetLaunchUrl(string? profileLaunchUrl, string outputLaunchU
Uri.TryCreate(outputLaunchUrl, UriKind.Absolute, out var launchUri) ? new Uri(launchUri, profileLaunchUrl).ToString() :
outputLaunchUrl;
- private void LaunchBrowser(string launchUrl, BrowserRefreshServer? server)
+ 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, BrowserRefreshServer? server)
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/BuiltInTools/dotnet-watch/Build/ProjectGraphUtilities.cs b/src/BuiltInTools/dotnet-watch/Build/ProjectGraphUtilities.cs
index ca8f616ebcce..56bcba3427e6 100644
--- a/src/BuiltInTools/dotnet-watch/Build/ProjectGraphUtilities.cs
+++ b/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/BuiltInTools/dotnet-watch/CommandLine/EnvironmentOptions.cs b/src/BuiltInTools/dotnet-watch/CommandLine/EnvironmentOptions.cs
index f2fbfa7cabd3..72f787332533 100644
--- a/src/BuiltInTools/dotnet-watch/CommandLine/EnvironmentOptions.cs
+++ b/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/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs b/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs
index cedccb2351f1..c29aee037ca2 100644
--- a/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs
+++ b/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);
+
+ RunningProject? publishedRunningProject = null;
- processSpec.OnExit += (_, _) =>
+ 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,129 @@ 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, isInitial: true, 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);
+
+ // More updates might have come in while we have been applying updates.
+ // If so, continue updating.
+ if (_previousUpdates.Count > appliedUpdateCount)
+ {
+ continue;
+ }
+
+ // 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;
}
+ }
- _runningProjects = _runningProjects.SetItem(projectPath, projectInstances.Add(runningProject));
+ clients.OnRuntimeRudeEdit += (code, message) =>
+ {
+ // fire and forget:
+ _ = HandleRuntimeRudeEditAsync(runningProject, message, cancellationToken);
+ };
- // ownership transferred to _runningProjects
- disposables.Items.Clear();
- break;
+ // 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)
+ {
+ // 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)
+ {
+ // 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;
+ }
+ }
- // Notifies the agent that it can unblock the execution of the process:
- await clients.InitialUpdatesAppliedAsync(cancellationToken);
+ private async Task HandleRuntimeRudeEditAsync(RunningProject runningProject, string rudeEditMessage, CancellationToken cancellationToken)
+ {
+ var logger = runningProject.Clients.ClientLogger;
- // If non-empty solution is loaded into the workspace (a Hot Reload session is active):
- if (Workspace.CurrentSolution is { ProjectIds: not [] } currentSolution)
+ try
{
- // Preparing the compilation is a perf optimization. We can skip it if the session hasn't been started yet.
- PrepareCompilations(currentSolution, projectPath, cancellationToken);
- }
+ // 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;
+ }
- return runningProject;
+ 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()
@@ -229,7 +286,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 +341,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 +369,10 @@ await ForEachProjectAsync(projectsToUpdate, async (runningProject, cancellationT
{
try
{
- using var processCommunicationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(runningProject.ProcessExitedSource.Token, cancellationToken);
- await runningProject.Clients.ApplyManagedCodeUpdatesAsync(ToManagedCodeUpdates(updates), isProcessSuspended: false, processCommunicationCancellationSource.Token);
+ using var processCommunicationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(runningProject.ProcessExitedCancellationToken, cancellationToken);
+ await runningProject.Clients.ApplyManagedCodeUpdatesAsync(ToManagedCodeUpdates(updates), isProcessSuspended: false, isInitial: 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 +420,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 +430,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 +494,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 +589,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 +601,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.TerminateForRestartAsync())).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 +670,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/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs b/src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs
index 764a371ab309..38e313f6f746 100644
--- a/src/BuiltInTools/dotnet-watch/HotReload/HotReloadDotNetWatcher.cs
+++ b/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,7 +127,8 @@ public async Task WatchAsync(CancellationToken shutdownCancellationToken)
rootProjectOptions,
rootProcessTerminationSource,
onOutput: null,
- restartOperation: new RestartOperation(_ => throw new InvalidOperationException("Root project shouldn't be restarted")),
+ onExit: null,
+ restartOperation: new RestartOperation(_ => default), // the process will automatically restart
iterationCancellationToken);
if (rootRunningProject == null)
@@ -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);
@@ -554,11 +539,10 @@ async Task> CaptureChangedFilesSnapshot(ImmutableArra
await runtimeProcessLauncher.DisposeAsync();
}
- rootRunningProject?.Dispose();
-
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/BuiltInTools/dotnet-watch/Process/ProcessRunner.cs b/src/BuiltInTools/dotnet-watch/Process/ProcessRunner.cs
index 3583dc07b8d8..54ae7d130229 100644
--- a/src/BuiltInTools/dotnet-watch/Process/ProcessRunner.cs
+++ b/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/BuiltInTools/dotnet-watch/Process/ProcessSpec.cs b/src/BuiltInTools/dotnet-watch/Process/ProcessSpec.cs
index b780f2770029..b3e1eaa1a6a6 100644
--- a/src/BuiltInTools/dotnet-watch/Process/ProcessSpec.cs
+++ b/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/BuiltInTools/dotnet-watch/Process/ProjectLauncher.cs b/src/BuiltInTools/dotnet-watch/Process/ProjectLauncher.cs
index 3299710fd18f..fb74333ebdd3 100644
--- a/src/BuiltInTools/dotnet-watch/Process/ProjectLauncher.cs
+++ b/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/BuiltInTools/dotnet-watch/Process/RunningProject.cs b/src/BuiltInTools/dotnet-watch/Process/RunningProject.cs
index 46ecd2c629a1..8f5bfe94b004 100644
--- a/src/BuiltInTools/dotnet-watch/Process/RunningProject.cs
+++ b/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,45 +32,84 @@ 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 => _isRestarting != 0;
+
+ private volatile int _isRestarting;
+ 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()
{
+ ObjectDisposedException.ThrowIf(_isDisposed, this);
+
+ _isDisposed = true;
+ processExitedSource.Cancel();
+
Clients.Dispose();
- ProcessTerminationSource.Dispose();
- ProcessExitedSource.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)
+ {
+ using var processCommunicationCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ProcessExitedCancellationToken);
- foreach (var disposable in _disposables)
+ try
{
- disposable.Dispose();
+ await Clients.WaitForConnectionEstablishedAsync(processCommunicationCancellationSource.Token);
+ return true;
+ }
+ catch (OperationCanceledException) when (ProcessExitedCancellationToken.IsCancellationRequested)
+ {
+ return false;
}
}
///
- /// Waits for the application process to start.
- /// Ensures that the build has been complete and the build outputs are available.
+ /// Terminates the process if it hasn't terminated yet.
///
- public async ValueTask WaitForProcessRunningAsync(CancellationToken cancellationToken)
+ public Task TerminateAsync()
{
- await Clients.WaitForConnectionEstablishedAsync(cancellationToken);
+ if (!_isDisposed)
+ {
+ processTerminationSource.Cancel();
+ }
+
+ return RunningProcess;
}
- public async ValueTask TerminateAsync()
+ ///
+ /// 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()
{
- ProcessTerminationSource.Cancel();
- return await RunningProcess;
+ InitiateRestart();
+ return TerminateAsync();
}
}
}
diff --git a/src/BuiltInTools/dotnet-watch/Program.cs b/src/BuiltInTools/dotnet-watch/Program.cs
index b2b9bd03bbd9..f67a360a3a32 100644
--- a/src/BuiltInTools/dotnet-watch/Program.cs
+++ b/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/BuiltInTools/dotnet-watch/Properties/launchSettings.json b/src/BuiltInTools/dotnet-watch/Properties/launchSettings.json
index b6981fd0ae9d..9e28729eb807 100644
--- a/src/BuiltInTools/dotnet-watch/Properties/launchSettings.json
+++ b/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/BuiltInTools/dotnet-watch/UI/ConsoleReporter.cs b/src/BuiltInTools/dotnet-watch/UI/ConsoleReporter.cs
index 84cc357ad35a..198e518590bb 100644
--- a/src/BuiltInTools/dotnet-watch/UI/ConsoleReporter.cs
+++ b/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/BuiltInTools/dotnet-watch/UI/IReporter.cs b/src/BuiltInTools/dotnet-watch/UI/IReporter.cs
index c6f64394da88..319fcc1740b0 100644
--- a/src/BuiltInTools/dotnet-watch/UI/IReporter.cs
+++ b/src/BuiltInTools/dotnet-watch/UI/IReporter.cs
@@ -209,9 +209,13 @@ 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 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/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs
index 69b532afb0bb..0c5aef161367 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs
+++ b/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/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs
index 97e7abd086c3..e0dca709ac3c 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs
+++ b/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/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs b/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs
index ecf9c58147f5..0b1407d3d11b 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs
+++ b/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/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx b/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx
index 01b59dfe8833..d08a680ebae1 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx
+++ b/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/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs b/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs
index 80ca23402914..f517a6b363ba 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs
+++ b/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/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf
index 45f6d58a1ba7..c65c0e782a66 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf
+++ b/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}
+ Výsledek analýzy následujícího kódu JSON byl 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/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf
index eb67ab8bf9bf..077b39b257a1 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf
+++ b/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}
+ Das Ergebnis der Analyse des folgenden JSON war „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/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf
index 748e66f30a00..83e578cc9901 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf
+++ b/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}
+ El resultado del análisis del siguiente JSON fue "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/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf
index d86722e36e60..321017f2a61c 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf
+++ b/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}
+ Le résultat de l'analyse du JSON suivant était « 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/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf
index 45d8e4f02e4e..37c751e7c39e 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf
+++ b/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}
+ Il risultato dell'analisi del file JSON seguente è '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/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf
index 2f9a5c77a259..58b3201670e9 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf
+++ b/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}
+ 次の JSON の解析結果は 'null' でした:
+
+{0}
+ {0} is the JSON that is being parsed.
+ Parent property path '{0}' could not be traversed.親プロパティのパス '{0}' を走査できませんでした。
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf
index 11699454506d..5367a26984e1 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf
+++ b/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}
+ 다음 JSON을 구문 분석한 결과는 'null'입니다.
+
+{0}
+ {0} is the JSON that is being parsed.
+ Parent property path '{0}' could not be traversed.'{0}' 부모 속성 경로를 트래버스할 수 없습니다.
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf
index 6e5167124b31..35d4691fba5e 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf
+++ b/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}
+ Wynikiem analizy następującego kodu JSON była wartość „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/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf
index 24f89179cb85..accfeb0309e1 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf
+++ b/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}
+ O resultado da análise sintática do JSON a seguir foi '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/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf
index 6578a4d5bf14..c5e680a97988 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf
+++ b/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}
+ Результат разбора следующего JSON оказался равен null:
+
+{0}
+ {0} is the JSON that is being parsed.
+ Parent property path '{0}' could not be traversed.Не удалось просмотреть путь к родительскому свойству "{0}".
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf
index a0d71cff2b96..ba424b44aa59 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf
+++ b/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}
+ Aşağıdaki JSON'un ayrıştırma sonucu 'null' idi:
+
+{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/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf
index f75d8ad68dae..e1820411d6c7 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf
+++ b/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}
+ 解析以下 JSON 会得到 "null":
+
+{0}
+ {0} is the JSON that is being parsed.
+ Parent property path '{0}' could not be traversed.无法遍历父属性路径“{0}”。
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf
index 56c64a9d9b91..5030f71d78cc 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf
+++ b/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}
+ 剖析下列 JSON 的結果為 'null':
+
+{0}
+ {0} is the JSON that is being parsed.
+ Parent property path '{0}' could not be traversed.無法周遊父屬性路徑 '{0}'。
diff --git a/src/Cli/dotnet/CliStrings.resx b/src/Cli/dotnet/CliStrings.resx
index ea37a0b0333e..7852c04414a0 100644
--- a/src/Cli/dotnet/CliStrings.resx
+++ b/src/Cli/dotnet/CliStrings.resx
@@ -841,4 +841,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/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx
index 6ca03e2f5fe6..ca7f6baf9f40 100644
--- a/src/Cli/dotnet/Commands/CliCommandStrings.resx
+++ b/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}...
@@ -1620,6 +1621,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'.
@@ -1995,8 +1999,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
@@ -2702,4 +2707,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/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs b/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs
index 67c2a47f1051..3055de0883f5 100644
--- a/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs
+++ b/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/Cli/dotnet/Commands/MSBuild/MSBuildForwardingLogger.cs b/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingLogger.cs
index fc7c6488b910..fef3e251bedc 100644
--- a/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingLogger.cs
+++ b/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingLogger.cs
@@ -26,11 +26,14 @@ public void Initialize(IEventSource eventSource)
eventSource4.IncludeEvaluationPropertiesAndItems();
}
- // Only forward telemetry events
+ // Forward telemetry events
if (eventSource is IEventSource2 eventSource2)
{
eventSource2.TelemetryLogged += (sender, args) => BuildEventRedirector.ForwardEvent(args);
}
+
+ // Forward build finished events. Is used for logging the aggregated build events.
+ eventSource.BuildFinished += (sender, args) => BuildEventRedirector.ForwardEvent(args);
}
public void Initialize(IEventSource eventSource, int nodeCount)
diff --git a/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs b/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs
index 1937f117cad2..2656f9798a9e 100644
--- a/src/Cli/dotnet/Commands/MSBuild/MSBuildLogger.cs
+++ b/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";
@@ -24,6 +22,10 @@ public sealed class MSBuildLogger : INodeLogger
internal const string BuildcheckRunEventName = "buildcheck/run";
internal const string BuildcheckRuleStatsEventName = "buildcheck/rule";
+ // These two events are aggregated and sent at the end of the build.
+ internal const string TaskFactoryTelemetryAggregatedEventName = "build/tasks/taskfactory";
+ internal const string TasksTelemetryAggregatedEventName = "build/tasks";
+
internal const string SdkTaskBaseCatchExceptionTelemetryEventName = "taskBaseCatchException";
internal const string PublishPropertiesTelemetryEventName = "PublishProperties";
internal const string WorkloadPublishPropertiesTelemetryEventName = "WorkloadPublishProperties";
@@ -50,11 +52,20 @@ public sealed class MSBuildLogger : INodeLogger
///
internal const string SdkContainerPublishErrorEventName = "sdk/container/publish/error";
+ ///
+ /// Stores aggregated telemetry data by event name and property name.
+ ///
+ ///
+ /// Key: event name, Value: property name to aggregated count.
+ /// Aggregation is very basic. Only integer properties are aggregated by summing values. Non-integer properties are ignored.
+ ///
+ private Dictionary> _aggregatedEvents = new();
+
public MSBuildLogger()
{
try
{
- string sessionId =
+ string? sessionId =
Environment.GetEnvironmentVariable(MSBuildForwardingApp.TelemetrySessionIdEnvironmentVariableName);
if (sessionId != null)
@@ -75,6 +86,14 @@ public MSBuildLogger()
}
}
+ ///
+ /// Constructor for testing purposes.
+ ///
+ internal MSBuildLogger(ITelemetry telemetry)
+ {
+ _telemetry = telemetry;
+ }
+
public void Initialize(IEventSource eventSource, int nodeCount)
{
Initialize(eventSource);
@@ -97,7 +116,11 @@ public void Initialize(IEventSource eventSource)
{
eventSource2.TelemetryLogged += OnTelemetryLogged;
}
+
+ eventSource.BuildFinished += OnBuildFinished;
}
+
+ eventSource.BuildFinished += OnBuildFinished;
}
catch (Exception)
{
@@ -105,38 +128,79 @@ public void Initialize(IEventSource eventSource)
}
}
- internal static void FormatAndSend(ITelemetry telemetry, TelemetryEventArgs args)
+ private void OnBuildFinished(object sender, BuildFinishedEventArgs e)
{
- switch (args.EventName)
+ SendAggregatedEventsOnBuildFinished(_telemetry);
+ }
+
+ internal void SendAggregatedEventsOnBuildFinished(ITelemetry? telemetry)
+ {
+ if (telemetry is null) return;
+ if (_aggregatedEvents.TryGetValue(TaskFactoryTelemetryAggregatedEventName, out var taskFactoryData))
{
- 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));
- }
- }
+ Dictionary taskFactoryProperties = ConvertToStringDictionary(taskFactoryData);
+
+ TrackEvent(telemetry, $"msbuild/{TaskFactoryTelemetryAggregatedEventName}", taskFactoryProperties, toBeHashed: [], toBeMeasured: []);
+ _aggregatedEvents.Remove(TaskFactoryTelemetryAggregatedEventName);
+ }
+
+ if (_aggregatedEvents.TryGetValue(TasksTelemetryAggregatedEventName, out var tasksData))
+ {
+ Dictionary tasksProperties = ConvertToStringDictionary(tasksData);
+
+ TrackEvent(telemetry, $"msbuild/{TasksTelemetryAggregatedEventName}", tasksProperties, toBeHashed: [], toBeMeasured: []);
+ _aggregatedEvents.Remove(TasksTelemetryAggregatedEventName);
+ }
+ }
+
+ private static Dictionary ConvertToStringDictionary(Dictionary properties)
+ {
+ Dictionary stringProperties = new();
+ foreach (var kvp in properties)
+ {
+ stringProperties[kvp.Key] = kvp.Value.ToString(CultureInfo.InvariantCulture);
+ }
+
+ return stringProperties;
+ }
- telemetry.TrackEvent(newEventName, maskedProperties, measurements: null);
- break;
+ internal void AggregateEvent(TelemetryEventArgs args)
+ {
+ if (args.EventName is null) return;
+ if (!_aggregatedEvents.TryGetValue(args.EventName, out Dictionary? eventData) || eventData is null)
+ {
+ eventData = new Dictionary();
+ _aggregatedEvents[args.EventName] = eventData;
+ }
+
+ foreach (var kvp in args.Properties)
+ {
+ if (int.TryParse(kvp.Value, CultureInfo.InvariantCulture, out int count))
+ {
+ if (!eventData.ContainsKey(kvp.Key))
+ {
+ eventData[kvp.Key] = count;
+ }
+ else
+ {
+ eventData[kvp.Key] += count;
}
+ }
+ }
+ }
+
+ internal static void FormatAndSend(ITelemetry? telemetry, TelemetryEventArgs args)
+ {
+ switch (args.EventName)
+ {
+ case TargetFrameworkTelemetryEventName:
+ 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,
@@ -145,18 +209,19 @@ internal static void FormatAndSend(ITelemetry telemetry, TelemetryEventArgs args
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:
@@ -166,7 +231,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
@@ -174,33 +239,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;
+ }
}
}
}
@@ -210,7 +286,14 @@ private static void TrackEvent(ITelemetry telemetry, string eventName, IDictiona
private void OnTelemetryLogged(object sender, TelemetryEventArgs args)
{
- FormatAndSend(_telemetry, args);
+ if (args.EventName == TaskFactoryTelemetryAggregatedEventName || args.EventName == TasksTelemetryAggregatedEventName)
+ {
+ AggregateEvent(args);
+ }
+ else
+ {
+ FormatAndSend(_telemetry, args);
+ }
}
public void Shutdown()
@@ -227,5 +310,5 @@ public void Shutdown()
public LoggerVerbosity Verbosity { get; set; }
- public string Parameters { get; set; }
+ public string? Parameters { get; set; }
}
diff --git a/src/Cli/dotnet/Commands/Package/Add/PackageAddCommand.cs b/src/Cli/dotnet/Commands/Package/Add/PackageAddCommand.cs
index d1c73fb5bb1e..dc94f892abd1 100644
--- a/src/Cli/dotnet/Commands/Package/Add/PackageAddCommand.cs
+++ b/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/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs b/src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs
index c166f61769fe..f1bc3ab7d655 100644
--- a/src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs
+++ b/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;
@@ -31,6 +32,16 @@ public override int Execute()
var sourceFile = SourceFile.Load(file);
var directives = VirtualProjectBuildingCommand.FindDirectives(sourceFile, reportAllErrors: !_force, DiagnosticBag.ThrowOnFirst());
+ // Create a project instance for evaluation.
+ var projectCollection = new ProjectCollection();
+ var command = new VirtualProjectBuildingCommand(
+ entryPointFileFullPath: file,
+ msbuildArgs: MSBuildArgs.FromOtherArgs([]))
+ {
+ Directives = directives,
+ };
+ var projectInstance = command.CreateProjectInstance(projectCollection);
+
// Find other items to copy over, e.g., default Content items like JSON files in Web apps.
var includeItems = FindIncludedItems().ToList();
@@ -61,7 +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);
+ VirtualProjectBuildingCommand.WriteProjectFile(writer, UpdateDirectives(directives), isVirtualProject: false,
+ userSecretsId: DetermineUserSecretsId(),
+ excludeDefaultProperties: FindDefaultPropertiesToExclude());
}
// Copy or move over included items.
@@ -112,14 +125,6 @@ void CopyFile(string source, string target)
IEnumerable<(string FullPath, string RelativePath)> FindIncludedItems()
{
string entryPointFileDirectory = PathUtility.EnsureTrailingSlash(Path.GetDirectoryName(file)!);
- var projectCollection = new ProjectCollection();
- var command = new VirtualProjectBuildingCommand(
- entryPointFileFullPath: file,
- msbuildArgs: MSBuildArgs.FromOtherArgs([]))
- {
- Directives = directives,
- };
- var projectInstance = command.CreateProjectInstance(projectCollection);
// Include only items we know are files.
string[] itemTypes = ["Content", "None", "Compile", "EmbeddedResource"];
@@ -151,6 +156,47 @@ void CopyFile(string source, string target)
yield return (FullPath: itemFullPath, RelativePath: itemRelativePath);
}
}
+
+ string? DetermineUserSecretsId()
+ {
+ var implicitValue = projectInstance.GetPropertyValue("_ImplicitFileBasedProgramUserSecretsId");
+ 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/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs b/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs
index ac20c4286ba0..84ac2b073fe0 100644
--- a/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs
+++ b/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs
@@ -110,9 +110,18 @@ public int Execute(out bool fallbackToNormalBuild)
if (BuildResultFile != null &&
CSharpCommandLineParser.Default.Parse(CscArguments, BaseDirectory, sdkDirectory: null) is { OutputFileName: { } outputFileName } parsedArgs)
{
- var objFile = parsedArgs.GetOutputFilePath(outputFileName);
- Reporter.Verbose.WriteLine($"Copying '{objFile}' to '{BuildResultFile}'.");
- File.Copy(objFile, BuildResultFile, overwrite: true);
+ var objFile = new FileInfo(parsedArgs.GetOutputFilePath(outputFileName));
+ var binFile = new FileInfo(BuildResultFile);
+
+ if (HaveMatchingSizeAndTimeStamp(objFile, binFile))
+ {
+ Reporter.Verbose.WriteLine($"Skipping copy of '{objFile}' to '{BuildResultFile}' because the files have matching size and timestamp.");
+ }
+ else
+ {
+ Reporter.Verbose.WriteLine($"Copying '{objFile}' to '{BuildResultFile}'.");
+ File.Copy(objFile.FullName, binFile.FullName, overwrite: true);
+ }
}
return exitCode;
@@ -153,6 +162,27 @@ static int ProcessBuildResponse(BuildResponse response, out bool fallbackToNorma
return 1;
}
}
+
+ // Inspired by MSBuild: https://github.com/dotnet/msbuild/blob/a7a4d5af02be5aa6dc93a492d6d03056dc811388/src/Tasks/Copy.cs#L208
+ static bool HaveMatchingSizeAndTimeStamp(FileInfo sourceFile, FileInfo destinationFile)
+ {
+ if (!destinationFile.Exists)
+ {
+ return false;
+ }
+
+ if (sourceFile.LastWriteTimeUtc != destinationFile.LastWriteTimeUtc)
+ {
+ return false;
+ }
+
+ if (sourceFile.Length != destinationFile.Length)
+ {
+ return false;
+ }
+
+ return true;
+ }
}
private void PrepareAuxiliaryFiles(out string rspPath)
diff --git a/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs b/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs
index dffbbc0bfab3..64d2b8a1075a 100644
--- a/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs
+++ b/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/Cli/dotnet/Commands/Run/FileBasedAppSourceEditor.cs b/src/Cli/dotnet/Commands/Run/FileBasedAppSourceEditor.cs
index 402da626784e..45fa0380aeea 100644
--- a/src/Cli/dotnet/Commands/Run/FileBasedAppSourceEditor.cs
+++ b/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/Cli/dotnet/Commands/Run/RunCommand.cs b/src/Cli/dotnet/Commands/Run/RunCommand.cs
index 3145f0e0b04b..9c11228ab213 100644
--- a/src/Cli/dotnet/Commands/Run/RunCommand.cs
+++ b/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;
@@ -397,7 +398,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 +464,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 +484,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)
{
@@ -497,6 +500,7 @@ static void InvokeRunArgumentsTarget(ProjectInstance project, bool noBuild, Faca
}
}
+ [DoesNotReturn]
internal static void ThrowUnableToRunError(ProjectInstance project)
{
string targetFrameworks = project.GetPropertyValue("TargetFrameworks");
@@ -833,11 +837,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)
{
@@ -846,10 +850,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);
}
@@ -878,10 +882,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")))
@@ -895,7 +899,7 @@ private void SendProjectBasedTelemetry(ProjectLaunchSettingsModel? launchSetting
{
// Ignore errors when trying to find repo root
}
-
+
return null;
}
}
diff --git a/src/Cli/dotnet/Commands/Run/RunProperties.cs b/src/Cli/dotnet/Commands/Run/RunProperties.cs
index 81e92cb88315..6972d140ac56 100644
--- a/src/Cli/dotnet/Commands/Run/RunProperties.cs
+++ b/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/Cli/dotnet/Commands/Run/RunTelemetry.cs b/src/Cli/dotnet/Commands/Run/RunTelemetry.cs
index 35e13b2d3fd2..1e58bdd27c05 100644
--- a/src/Cli/dotnet/Commands/Run/RunTelemetry.cs
+++ b/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/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs b/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs
index 6997b8052a0c..5119a2b579df 100644
--- a/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs
+++ b/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;
@@ -353,11 +354,20 @@ 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;
- 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 +454,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))
@@ -897,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;
}
@@ -1138,8 +1142,13 @@ public static void WriteProjectFile(
bool isVirtualProject,
string? targetFilePath = null,
string? artifactsPath = null,
- bool includeRuntimeConfigInformation = true)
+ bool includeRuntimeConfigInformation = true,
+ string? userSecretsId = null,
+ IEnumerable? excludeDefaultProperties = null)
{
+ Debug.Assert(userSecretsId == null || !isVirtualProject);
+ Debug.Assert(excludeDefaultProperties == null || !isVirtualProject);
+
int processedDirectives = 0;
var sdkDirectives = directives.OfType();
@@ -1178,6 +1187,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)}{name}>
+ """);
+ }
+
+ writer.WriteLine($"""
@@ -1244,27 +1267,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)}{name}>
+ """);
+ }
+ }
+
+ if (userSecretsId != null && !customPropertyNames.Contains("UserSecretsId"))
{
writer.WriteLine($"""
- <{name}>{EscapeValue(value)}{name}>
+ {EscapeValue(userSecretsId)}
""");
}
}
- // Write virtual-only properties.
- if (isVirtualProject)
- {
- writer.WriteLine("""
- false
- true
- false
- """);
- }
-
// Write custom properties.
foreach (var property in propertyDirectives)
{
@@ -1279,6 +1305,7 @@ public static void WriteProjectFile(
if (isVirtualProject)
{
writer.WriteLine("""
+ false$(Features);FileBasedProgram
""");
}
@@ -1480,8 +1507,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.
@@ -1723,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())
@@ -1738,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());
}
@@ -1877,7 +1919,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))
{
@@ -1895,6 +1941,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/Cli/dotnet/Commands/Test/MTP/Terminal/AnsiTerminalTestProgressFrame.cs b/src/Cli/dotnet/Commands/Test/MTP/Terminal/AnsiTerminalTestProgressFrame.cs
index 6a6974bd97f1..822b0c4e9791 100644
--- a/src/Cli/dotnet/Commands/Test/MTP/Terminal/AnsiTerminalTestProgressFrame.cs
+++ b/src/Cli/dotnet/Commands/Test/MTP/Terminal/AnsiTerminalTestProgressFrame.cs
@@ -26,60 +26,78 @@ public void AppendTestWorkerProgress(TestProgressState progress, RenderedProgres
int nonReservedWidth = Width - (durationString.Length + 2);
+ int discovered = progress.DiscoveredTests;
int passed = progress.PassedTests;
int failed = progress.FailedTests;
int skipped = progress.SkippedTests;
int retried = progress.RetriedFailedTests;
int charsTaken = 0;
- terminal.Append('[');
- charsTaken++;
- terminal.SetColor(TerminalColor.DarkGreen);
- terminal.Append('✓');
- charsTaken++;
- string passedText = passed.ToString(CultureInfo.CurrentCulture);
- terminal.Append(passedText);
- charsTaken += passedText.Length;
- terminal.ResetColor();
+ if (!progress.IsDiscovery)
+ {
+ terminal.Append('[');
+ charsTaken++;
+ terminal.SetColor(TerminalColor.DarkGreen);
+ terminal.Append('✓');
+ charsTaken++;
+ string passedText = passed.ToString(CultureInfo.CurrentCulture);
+ terminal.Append(passedText);
+ charsTaken += passedText.Length;
+ terminal.ResetColor();
- terminal.Append('/');
- charsTaken++;
+ terminal.Append('/');
+ charsTaken++;
- terminal.SetColor(TerminalColor.DarkRed);
- terminal.Append('x');
- charsTaken++;
- string failedText = failed.ToString(CultureInfo.CurrentCulture);
- terminal.Append(failedText);
- charsTaken += failedText.Length;
- terminal.ResetColor();
+ terminal.SetColor(TerminalColor.DarkRed);
+ terminal.Append('x');
+ charsTaken++;
+ string failedText = failed.ToString(CultureInfo.CurrentCulture);
+ terminal.Append(failedText);
+ charsTaken += failedText.Length;
+ terminal.ResetColor();
- terminal.Append('/');
- charsTaken++;
+ terminal.Append('/');
+ charsTaken++;
- terminal.SetColor(TerminalColor.DarkYellow);
- terminal.Append('↓');
- charsTaken++;
- string skippedText = skipped.ToString(CultureInfo.CurrentCulture);
- terminal.Append(skippedText);
- charsTaken += skippedText.Length;
- terminal.ResetColor();
+ terminal.SetColor(TerminalColor.DarkYellow);
+ terminal.Append('↓');
+ charsTaken++;
+ string skippedText = skipped.ToString(CultureInfo.CurrentCulture);
+ terminal.Append(skippedText);
+ charsTaken += skippedText.Length;
+ terminal.ResetColor();
+
+ if (retried > 0)
+ {
+ terminal.Append('/');
+ charsTaken++;
+ terminal.SetColor(TerminalColor.Gray);
+ terminal.Append('r');
+ charsTaken++;
+ string retriedText = retried.ToString(CultureInfo.CurrentCulture);
+ terminal.Append(retriedText);
+ charsTaken += retriedText.Length;
+ terminal.ResetColor();
+ }
- if (retried > 0)
+ terminal.Append(']');
+ charsTaken++;
+ }
+ else
{
- terminal.Append('/');
+ string discoveredText = progress.DiscoveredTests.ToString(CultureInfo.CurrentCulture);
+ terminal.Append('[');
charsTaken++;
- terminal.SetColor(TerminalColor.Gray);
- terminal.Append('r');
+ terminal.SetColor(TerminalColor.DarkMagenta);
+ terminal.Append('+');
charsTaken++;
- string retriedText = retried.ToString(CultureInfo.CurrentCulture);
- terminal.Append(retriedText);
- charsTaken += retriedText.Length;
+ terminal.Append(discoveredText);
+ charsTaken += discoveredText.Length;
terminal.ResetColor();
+ terminal.Append(']');
+ charsTaken++;
}
- terminal.Append(']');
- charsTaken++;
-
terminal.Append(' ');
charsTaken++;
AppendToWidth(terminal, progress.AssemblyName, nonReservedWidth, ref charsTaken);
diff --git a/src/Cli/dotnet/Commands/Test/MTP/Terminal/HumanReadableDurationFormatter.cs b/src/Cli/dotnet/Commands/Test/MTP/Terminal/HumanReadableDurationFormatter.cs
index 559af6b77847..304166341323 100644
--- a/src/Cli/dotnet/Commands/Test/MTP/Terminal/HumanReadableDurationFormatter.cs
+++ b/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/Cli/dotnet/Commands/Test/MTP/Terminal/SimpleTerminalBase.cs b/src/Cli/dotnet/Commands/Test/MTP/Terminal/SimpleTerminalBase.cs
index 310b3edd271e..760aff97d746 100644
--- a/src/Cli/dotnet/Commands/Test/MTP/Terminal/SimpleTerminalBase.cs
+++ b/src/Cli/dotnet/Commands/Test/MTP/Terminal/SimpleTerminalBase.cs
@@ -67,32 +67,49 @@ public void RenderProgress(TestProgressState?[] progress)
string durationString = HumanReadableDurationFormatter.Render(p.Stopwatch.Elapsed);
+ int discovered = p.DiscoveredTests;
int passed = p.PassedTests;
int failed = p.FailedTests;
int skipped = p.SkippedTests;
- // Use just ascii here, so we don't put too many restrictions on fonts needing to
- // properly show unicode, or logs being saved in particular encoding.
- Append('[');
- SetColor(TerminalColor.DarkGreen);
- Append('+');
- Append(passed.ToString(CultureInfo.CurrentCulture));
- ResetColor();
+ if (!p.IsDiscovery)
+ {
+ // Use just ascii here, so we don't put too many restrictions on fonts needing to
+ // properly show unicode, or logs being saved in particular encoding.
+ Append('[');
+ SetColor(TerminalColor.DarkGreen);
+ Append('+');
+ Append(passed.ToString(CultureInfo.CurrentCulture));
+ ResetColor();
+
+ Append('/');
- Append('/');
+ SetColor(TerminalColor.DarkRed);
+ Append('x');
+ Append(failed.ToString(CultureInfo.CurrentCulture));
+ ResetColor();
- SetColor(TerminalColor.DarkRed);
- Append('x');
- Append(failed.ToString(CultureInfo.CurrentCulture));
- ResetColor();
+ Append('/');
- Append('/');
+ SetColor(TerminalColor.DarkYellow);
+ Append('?');
+ Append(skipped.ToString(CultureInfo.CurrentCulture));
+ ResetColor();
- SetColor(TerminalColor.DarkYellow);
- Append('?');
- Append(skipped.ToString(CultureInfo.CurrentCulture));
- ResetColor();
- Append(']');
+ Append(']');
+ }
+ else
+ {
+ // Use just ascii here, so we don't put too many restrictions on fonts needing to
+ // properly show unicode, or logs being saved in particular encoding.
+ Append('[');
+ SetColor(TerminalColor.DarkMagenta);
+ Append('+');
+ Append(discovered.ToString(CultureInfo.CurrentCulture));
+ ResetColor();
+
+ Append(']');
+ }
Append(' ');
Append(p.AssemblyName);
diff --git a/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs b/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs
index 4494ea61535c..22929d8dfb7f 100644
--- a/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs
+++ b/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs
@@ -139,7 +139,7 @@ private TestProgressState GetOrAddAssemblyRun(string assembly, string? targetFra
return _assemblies.GetOrAdd(executionId, _ =>
{
IStopwatch sw = CreateStopwatch();
- var assemblyRun = new TestProgressState(Interlocked.Increment(ref _counter), assembly, targetFramework, architecture, sw);
+ var assemblyRun = new TestProgressState(Interlocked.Increment(ref _counter), assembly, targetFramework, architecture, sw, _isDiscovery);
int slotIndex = _terminalWithProgress.AddWorker(assemblyRun);
assemblyRun.SlotIndex = slotIndex;
@@ -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)
{
@@ -801,7 +801,7 @@ void AppendOutputWhenPresent(string description, string? output)
private static void AppendAssemblySummary(TestProgressState assemblyRun, ITerminal terminal)
{
terminal.ResetColor();
-
+
AppendAssemblyLinkTargetFrameworkAndArchitecture(terminal, assemblyRun.Assembly, assemblyRun.TargetFramework, assemblyRun.Architecture);
terminal.Append(' ');
AppendAssemblyResult(terminal, assemblyRun);
@@ -914,15 +914,15 @@ public void AppendTestDiscoverySummary(ITerminal terminal, int? exitCode)
var assemblies = _assemblies.Select(asm => asm.Value).OrderBy(a => a.Assembly).Where(a => a is not null).ToList();
int totalTests = _assemblies.Values.Sum(a => a.TotalTests);
- bool runFailed = _wasCancelled;
+ bool runFailed = _wasCancelled || totalTests < 1;
foreach (TestProgressState assembly in assemblies)
{
- terminal.Append(string.Format(CultureInfo.CurrentCulture, CliCommandStrings.DiscoveredTestsInAssembly, assembly.DiscoveredTests.Count));
+ terminal.Append(string.Format(CultureInfo.CurrentCulture, CliCommandStrings.DiscoveredTestsInAssembly, assembly.DiscoveredTestNames.Count));
terminal.Append(" - ");
AppendAssemblyLinkTargetFrameworkAndArchitecture(terminal, assembly.Assembly, assembly.TargetFramework, assembly.Architecture);
terminal.AppendLine();
- foreach ((string? displayName, string? uid) in assembly.DiscoveredTests)
+ foreach ((string? displayName, string? uid) in assembly.DiscoveredTestNames)
{
if (displayName is not null)
{
diff --git a/src/Cli/dotnet/Commands/Test/MTP/Terminal/TestProgressState.cs b/src/Cli/dotnet/Commands/Test/MTP/Terminal/TestProgressState.cs
index a39d0a0fbe48..fd801f6a5a6c 100644
--- a/src/Cli/dotnet/Commands/Test/MTP/Terminal/TestProgressState.cs
+++ b/src/Cli/dotnet/Commands/Test/MTP/Terminal/TestProgressState.cs
@@ -6,7 +6,7 @@
namespace Microsoft.DotNet.Cli.Commands.Test.Terminal;
-internal sealed class TestProgressState(long id, string assembly, string? targetFramework, string? architecture, IStopwatch stopwatch)
+internal sealed class TestProgressState(long id, string assembly, string? targetFramework, string? architecture, IStopwatch stopwatch, bool isDiscovery)
{
private readonly Dictionary _testUidToResults = new();
@@ -24,13 +24,15 @@ internal sealed class TestProgressState(long id, string assembly, string? target
public IStopwatch Stopwatch { get; } = stopwatch;
+ public int DiscoveredTests { get; private set; }
+
public int FailedTests { get; private set; }
public int PassedTests { get; private set; }
public int SkippedTests { get; private set; }
- public int TotalTests => PassedTests + SkippedTests + FailedTests;
+ public int TotalTests => IsDiscovery ? DiscoveredTests : PassedTests + SkippedTests + FailedTests;
public int RetriedFailedTests { get; private set; }
@@ -42,10 +44,12 @@ internal sealed class TestProgressState(long id, string assembly, string? target
public long Version { get; internal set; }
- public List<(string? DisplayName, string? UID)> DiscoveredTests { get; internal set; } = [];
+ public List<(string? DisplayName, string? UID)> DiscoveredTestNames { get; internal set; } = [];
public bool Success { get; internal set; }
+ public bool IsDiscovery = isDiscovery;
+
public int TryCount { get; private set; }
private void ReportGenericTestResult(
@@ -122,8 +126,8 @@ public void ReportFailedTest(string testNodeUid, string instanceId)
public void DiscoverTest(string? displayName, string? uid)
{
- PassedTests++;
- DiscoveredTests.Add(new(displayName, uid));
+ DiscoveredTests++;
+ DiscoveredTestNames.Add(new(displayName, uid));
}
internal void NotifyHandshake(string instanceId)
diff --git a/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs b/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs
index fc181b155db4..16ca1bb218e7 100644
--- a/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs
+++ b/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/Cli/dotnet/Commands/Test/TestCommandParser.cs b/src/Cli/dotnet/Commands/Test/TestCommandParser.cs
index 0fb00c0de94d..db52e8975ed3 100644
--- a/src/Cli/dotnet/Commands/Test/TestCommandParser.cs
+++ b/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/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs b/src/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs
index cf082e5e052e..a17cc0031e13 100644
--- a/src/Cli/dotnet/Commands/Test/VSTest/TestCommand.cs
+++ b/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/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
index d1d8709624e6..664772b545bc 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
+++ b/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
+ chybaUsed 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.
+ 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.
+ 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"}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:
+ doba trvání:
+
+
+
+ error:
+ chyba:
+
+ 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:
+ neúspěšné:
+
+ failedselhalo
@@ -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 (").
+ Direktivy v současné době nemůžou obsahovat dvojité uvozovky (").
+
+ 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
+ zkoušeno opakovaně
+
+ 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:
+ přeskočeno:
+
+ skippedvynechá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:
+ úspěšné:
+
+ SummarySouhrn
@@ -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
-
- Run test(s), without displaying Microsoft Testplatform bannerSpustit testy bez zobrazení nápisu Microsoft Testplatform
@@ -3557,6 +3592,11 @@ příkazu „dotnet tool list“.
Nástroj {0} byl úspěšně aktualizován z verze {1} na verzi {2}.
+
+ total:
+ celkem:
+
+ try {0}{0} pokus
@@ -3564,22 +3604,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.
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
index 2a39befb9d3c..4103532aa52e 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
+++ b/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
+ FehlerUsed 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-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-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"}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:
+ Dauer:
+
+
+
+ error:
+ Fehler:
+
+ 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:
+ fehlgeschlagen:
+
+ failedfehlerhaft
@@ -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 beendetThe 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 (").
+ Direktiven dürfen derzeit keine doppelten Anführungszeichen (") enthalten.
+
+ 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
+ Wiederholung
+
+ 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:
+ übersprungen:
+
+ 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:
+ erfolgreich:
+
+ SummaryZusammenfassung
@@ -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
-
- Run test(s), without displaying Microsoft Testplatform bannerTest(s) ohne Anzeige des Microsoft-Testplattformbanners ausführen
@@ -3557,6 +3592,11 @@ und die zugehörigen Paket-IDs für installierte Tools über den Befehl
Das Tool "{0}" wurde erfolgreich von Version {1} auf Version {2} aktualisiert.
+
+ total:
+ gesamt:
+
+ try {0}{0} testen
@@ -3564,22 +3604,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.
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
index 84f4aabb9069..38af98cfcc4b 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
+++ b/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
+ errorUsed 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.
+ 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.
+ 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"}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:
+ duración:
+
+
+
+ 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:
+ error:
+
+ failedcon 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ó correctamenteThe 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 (").
+ Las directivas no pueden contener comillas dobles ("), por ahora.
+
+ 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
+ volver a intentarlo
+
+ 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:
+ omitido:
+
+ skippedomitido
@@ -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:
+ correcto:
+
+ SummaryResumen
@@ -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
-
- Run test(s), without displaying Microsoft Testplatform bannerEjecutar pruebas, sin mostrar la pancarta de Microsoft Testplatform
@@ -3557,6 +3592,11 @@ y los identificadores de los paquetes correspondientes a las herramientas instal
La herramienta "{0}" se actualizó correctamente de la versión"{1}" a la versión "{2}".
+
+ total:
+ total:
+
+ try {0}intento {0}
@@ -3564,22 +3604,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.
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
index 6a637323a60e..f5fd10e7b624 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
+++ b/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
+ erreurUsed 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.
+ 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.
+ 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"}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:
+ durée :
+
+
+
+ error:
+ erreur :
+
+ 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:
+ échec :
+
+ 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 correctementThe 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 (").
+ Les directives ne peuvent actuellement pas contenir de guillemets doubles (").
+
+ 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
+ réessayé
+
+ 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:
+ ignoré :
+
+ skippedignoré
@@ -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:
+ réussie :
+
+ SummaryRé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
-
- Run test(s), without displaying Microsoft Testplatform bannerExécute le ou les tests, sans afficher la bannière Microsoft Testplatform
@@ -3557,6 +3592,11 @@ et les ID de package correspondants aux outils installés, utilisez la commande
L'outil '{0}' a été correctement mis à jour de la version '{1}' à la version '{2}'.
+
+ total:
+ total :
+
+ try {0}essayer {0}
@@ -3564,22 +3604,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.
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
index 1f255f43c794..620d7f8c6702 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
+++ b/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
+ erroreUsed 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.
+ 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.
+ 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"}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:
+ durata:
+
+
+
+ error:
+ errore:
+
+ 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:
+ non riuscito:
+
+ failedoperazione 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 correttamenteThe 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 (").
+ Le direttive attualmente non possono contenere virgolette doppie (").
+
+ 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
+ ripetuto
+
+ 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:
+ ignorato:
+
+ skippedignorato
@@ -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:
+ operazione completata:
+
+ SummaryRiepilogo
@@ -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
-
- Run test(s), without displaying Microsoft Testplatform bannerEsegui test senza visualizzare il banner di Microsoft Testplatform
@@ -3557,6 +3592,11 @@ e gli ID pacchetto corrispondenti per gli strumenti installati usando il comando
Lo strumento '{0}' è stato aggiornato dalla versione '{1}' alla versione '{2}'.
+
+ total:
+ totale:
+
+ try {0}prova {0}
@@ -3564,22 +3604,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.
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
index 7aa8108b6954..83e20d22eaa7 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
+++ b/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.
+ 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.
+ VSTest 用の .NET テスト コマンド。Microsoft.Testing.Platform を使用するには、global.json ファイルで Microsoft.Testing.Platform ベースのコマンドにオプトインしてください。詳細については、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:
+ 期間:
+
+
+
+ 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失敗
@@ -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 (").
+ ディレクティブには二重引用符 (") を含めることはできません。
+
+ Shut down the Razor build server.Razor ビルド サーバーをシャットダウンします。
@@ -2672,6 +2697,11 @@ The default is to publish a framework-dependent application.
ツール '{0}' (バージョン '{1}') は復元されました。使用できるコマンド: {2}
+
+ 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スキップされました
@@ -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:
+ 成功:
+
+ Summary概要
@@ -3101,11 +3141,6 @@ Your project targets multiple frameworks. Specify which framework to run using '
このコマンドに NuGet パッケージをダウンロードして抽出するための一時ディレクトリを指定します (セキュリティで保護する必要があります)。
-
- .NET Test Driver
- .NET Test Driver
-
- Run test(s), without displaying Microsoft Testplatform bannerMicrosoft Testplatform バナーを表示せずにテストを実行する
@@ -3557,6 +3592,11 @@ and the corresponding package Ids for installed tools using the command
ツール '{0}' がバージョン '{1}' からバージョン '{2}' に正常に更新されました。
+
+ total:
+ 合計:
+
+ try {0}{0} を試す
@@ -3564,22 +3604,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.
+ 対応するテスト セッションの開始がないまま、テスト セッション終了イベントを受信しました。
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
index 6544ed0d7051..c8d8d8f1b0ae 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
+++ b/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.
+ 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.
+ VSTest에 대한 .NET 테스트 명령입니다. Microsoft.Testing.Platform을 사용하려면 global.json을 통해 Microsoft.Testing.Platform 기반 명령을 옵트인합니다. 자세한 내용은 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:
+ 기간:
+
+
+
+ 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실패
@@ -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 (").
+ 지시문은 현재 큰따옴표(")를 포함할 수 없습니다.
+
+ Shut down the Razor build server.Razor 빌드 서버를 종료합니다.
@@ -2672,6 +2697,11 @@ The default is to publish a framework-dependent application.
'{0}' 도구(버전 '{1}')가 복원되었습니다. 사용 가능한 명령: {2}
+
+ 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건너뜀
@@ -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:
+ 성공:
+
+ Summary요약
@@ -3101,11 +3141,6 @@ Your project targets multiple frameworks. Specify which framework to run using '
NuGet 패키지를 다운로드하고 추출하려면 이 명령의 임시 디렉터리를 지정합니다(보안이 있어야 합니다).
-
- .NET Test Driver
- .NET 테스트 드라이버
-
- Run test(s), without displaying Microsoft Testplatform bannerMicrosoft Testplatform 배너를 표시하지 않고 테스트 실행
@@ -3557,6 +3592,11 @@ and the corresponding package Ids for installed tools using the command
'{0}' 도구가 '{1}' 버전에서 '{2}' 버전으로 업데이트되었습니다.
+
+ total:
+ 합계:
+
+ try {0}{0} 시도
@@ -3564,22 +3604,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.
+ 해당 테스트 세션을 시작하지 않고 테스트 세션 종료 이벤트를 받았습니다.
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
index 6e7de9021244..e1f846423119 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
+++ b/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łądUsed 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.
+ 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.
+ 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"}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:
+ czas trwania:
+
+
+
+ error:
+ błąd:
+
+ 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:
+ zakończone niepowodzeniem:
+
+ failedzakoń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ślnieThe 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 (").
+ Dyrektywy nie mogą obecnie zawierać podwójnych cudzysłowów (").
+
+ 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
+ próbowano ponownie
+
+ 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:
+ pominięto:
+
+ skippedpominię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:
+ zakończone powodzeniem:
+
+ SummaryPodsumowanie
@@ -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
-
- Run test(s), without displaying Microsoft Testplatform bannerUruchom testy bez wyświetlania baneru platformy testowej firmy Microsoft
@@ -3557,6 +3592,11 @@ i odpowiednie identyfikatory pakietów zainstalowanych narzędzi można znaleź
Narzędzie „{0}” zostało pomyślnie zaktualizowane z wersji „{1}” do wersji „{2}”.
+
+ total:
+ suma:
+
+ try {0}wypróbuj {0}
@@ -3564,22 +3604,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.
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
index 032d2caf149f..2d70a623e631 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
+++ b/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
+ erroUsed 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.
+ 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.
+ 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"}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:
+ duração:
+
+
+
+ error:
+ erro:
+
+ 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:
+ falhou:
+
+ failedcom 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 sucessoThe 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 (").
+ No momento, as diretivas não podem conter aspas duplas (").
+
+ 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
+ repetido
+
+ 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:
+ ignorados:
+
+ skippedignorado
@@ -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:
+ concluído com êxito:
+
+ SummaryResumo
@@ -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
-
- Run test(s), without displaying Microsoft Testplatform bannerExecutar testes, sem exibir a faixa do Microsoft Testplatform
@@ -3557,6 +3592,11 @@ e as Ids de pacote correspondentes para as ferramentas instaladas usando o coman
A ferramenta '{0}' foi atualizada com êxito da versão '{1}' para a versão '{2}'.
+
+ total:
+ total:
+
+ try {0}experimente {0}
@@ -3564,22 +3604,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.
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
index 05edfdd693ef..444910b3ef42 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
+++ b/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 для 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 для VSTest. Чтобы использовать Microsoft.Testing.Platform, согласитесь на использование команды на основе Microsoft.Testing.Platform посредством global.json. Дополнительные сведения см. на странице 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:
+ длительность:
+
+
+
+ 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сбой
@@ -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 (").
+ В директивах пока нельзя использовать двойные кавычки (").
+
+ Shut down the Razor build server.Завершает работу сервера сборки Razor.
@@ -2672,6 +2697,11 @@ The default is to publish a framework-dependent application.
Средство "{0}" (версия "{1}") было восстановлено. Доступные команды: {2}
+
+ 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пропущено
@@ -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:
+ успешно:
+
+ SummaryСводка
@@ -3101,11 +3141,6 @@ Your project targets multiple frameworks. Specify which framework to run using '
Укажите временный каталог для этой команды, чтобы скачать и извлечь пакеты NuGet (должны быть защищены).
-
- .NET Test Driver
- Драйвер тестов .NET
-
- Run test(s), without displaying Microsoft Testplatform bannerЗапуск тестов без отображения баннера Testplatform Майкрософт
@@ -3558,6 +3593,11 @@ and the corresponding package Ids for installed tools using the command
Инструмент "{0}" успешно обновлен с версии "{1}" до версии "{2}".
+
+ total:
+ итог:
+
+ try {0}попробуйте {0}
@@ -3565,22 +3605,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.
+ Получено событие завершения тестового сеанса без соответствующего запуска тестового сеанса.
@@ -3600,7 +3640,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/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
index 228d3a11bd02..6ebaaf56fa46 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
+++ b/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
+ hataUsed 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.
+ 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.
+ 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"}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:
+ süre:
+
+
+
+ error:
+ hata:
+
+ 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:
+ başarısız oldu:
+
+ failedbaş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 (").
+ Yönergeler şu anda çift tırnak (") içeremez.
+
+ 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
+ yeniden denendi
+
+ 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:
+ atlandı:
+
+ skippedatlandı
@@ -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:
+ başarılı:
+
+ 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ü
-
- Run test(s), without displaying Microsoft Testplatform bannerTestleri Microsoft Testplatform bandını görüntülemeden çalıştır
@@ -3557,6 +3592,11 @@ karşılık gelen paket kimliklerini bulmak için
'{0}' aracı, '{1}' sürümünden '{2}' sürümüne başarıyla güncelleştirildi.
+
+ total:
+ toplam:
+
+ try {0}Şunu deneyin: {0}
@@ -3564,22 +3604,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ı.
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
index 8dce87da752d..e439d651aa18 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
+++ b/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.
+ 适用于 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.
+ 适用于 VSTest 的 .NET 测试命令。若要使用 Microsoft.Testing.Platform,请通过 global.json 选择加入基于 Microsoft.Testing.Platform 的命令。有关详细信息,请参阅 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:
+ 持续时间:
+
+
+
+ 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失败
@@ -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 (").
+ 指令当前不能包含双引号(")。
+
+ Shut down the Razor build server.关闭 Razor 生成服务器。
@@ -2672,6 +2697,11 @@ The default is to publish a framework-dependent application.
工具“{0}”(版本“{1}”)已还原。可用的命令: {2}
+
+ 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已跳过
@@ -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:
+ 成功:
+
+ Summary摘要
@@ -3101,11 +3141,6 @@ Your project targets multiple frameworks. Specify which framework to run using '
为此命令指定一个临时目录,以下载并提取(必须安全)的 NuGet 包。
-
- .NET Test Driver
- .NET 测试驱动程序
-
- Run test(s), without displaying Microsoft Testplatform banner运行测试,而不显示 Microsoft Testplatform 版权标志
@@ -3557,6 +3592,11 @@ and the corresponding package Ids for installed tools using the command
工具“{0}”已成功从版本“{1}”更新到版本“{2}”。
+
+ total:
+ 总计:
+
+ try {0}尝试 {0}
@@ -3564,22 +3604,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.
+ 在没有相应的测试会话启动的情况下收到了测试会话结束事件。
@@ -3599,7 +3639,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/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
index 4402fa7bc229..78164f6aef22 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
+++ b/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 測試命令,適用於 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.
+ 適用於 VSTest 的 .NET 測試命令。若要使用 Microsoft.Testing.Platform,請透過 global.json 選擇加入以 Microsoft.Testing.Platform 為基礎的命令。如需詳細資訊,請參閱 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:
+ 期間:
+
+
+
+ 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已失敗
@@ -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 (").
+ 指令目前不能包含雙引號 (")。
+
+ Shut down the Razor build server.關閉 Razor 組建伺服器。
@@ -2672,6 +2697,11 @@ The default is to publish a framework-dependent application.
已還原工具 '{0}' (版本 '{1}')。可用的命令: {2}
+
+ 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已跳過
@@ -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:
+ 已成功:
+
+ Summary摘要
@@ -3101,11 +3141,6 @@ Your project targets multiple frameworks. Specify which framework to run using '
指定此命令的暫存目錄,以下載並解壓縮 NuGet 套件 (必須為安全)。
-
- .NET Test Driver
- .NET 測試驅動程式
-
- Run test(s), without displaying Microsoft Testplatform banner執行測試,但不顯示 Microsoft Testplatform 橫幅
@@ -3557,6 +3592,11 @@ and the corresponding package Ids for installed tools using the command
已成功將工具 '{0}' 從 '{1}' 版更新為 '{2}' 版。
+
+ total:
+ 總計:
+
+ try {0}嘗試 {0}
@@ -3564,22 +3604,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.
+ 收到測試工作階段結束事件,但沒有對應的測試工作階段開始。
@@ -3599,7 +3639,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/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs b/src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs
index 8ac89af40212..a311e88c646d 100644
--- a/src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs
+++ b/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/Cli/dotnet/Program.cs b/src/Cli/dotnet/Program.cs
index cd82a15330f4..e57fe3a5635f 100644
--- a/src/Cli/dotnet/Program.cs
+++ b/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/Cli/dotnet/Telemetry/EnvironmentDetectionRule.cs b/src/Cli/dotnet/Telemetry/EnvironmentDetectionRule.cs
index 5cd73f53abb8..079b8d287d3a 100644
--- a/src/Cli/dotnet/Telemetry/EnvironmentDetectionRule.cs
+++ b/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,7 +96,7 @@ 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)))
+ return _rule.IsMatch()
? _result
: null;
}
diff --git a/src/Cli/dotnet/Telemetry/ILLMEnvironmentDetector.cs b/src/Cli/dotnet/Telemetry/ILLMEnvironmentDetector.cs
index fe599569aa6c..ed7db2596f88 100644
--- a/src/Cli/dotnet/Telemetry/ILLMEnvironmentDetector.cs
+++ b/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();
+
+ ///
+ /// Returns true if the current environment is detected to be an LLM/agentic environment, false otherwise.
+ ///
+ bool IsLLMEnvironment();
}
\ No newline at end of file
diff --git a/src/Cli/dotnet/Telemetry/LLMEnvironmentDetectorForTelemetry.cs b/src/Cli/dotnet/Telemetry/LLMEnvironmentDetectorForTelemetry.cs
index 16d13a6879e7..78111c753f30 100644
--- a/src/Cli/dotnet/Telemetry/LLMEnvironmentDetectorForTelemetry.cs
+++ b/src/Cli/dotnet/Telemetry/LLMEnvironmentDetectorForTelemetry.cs
@@ -10,14 +10,24 @@ 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;
}
+
+ ///
+ public bool IsLLMEnvironment() => !string.IsNullOrEmpty(GetLLMEnvironment());
}
\ No newline at end of file
diff --git a/src/Cli/dotnet/xlf/CliStrings.cs.xlf b/src/Cli/dotnet/xlf/CliStrings.cs.xlf
index bc8118692866..ce6d0b3db1c6 100644
--- a/src/Cli/dotnet/xlf/CliStrings.cs.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.cs.xlf
@@ -373,6 +373,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}
diff --git a/src/Cli/dotnet/xlf/CliStrings.de.xlf b/src/Cli/dotnet/xlf/CliStrings.de.xlf
index 6157c0b591d4..5a2530e967c4 100644
--- a/src/Cli/dotnet/xlf/CliStrings.de.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.de.xlf
@@ -102,7 +102,6 @@ Examples:
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.
Beispiele:
@@ -373,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}
diff --git a/src/Cli/dotnet/xlf/CliStrings.es.xlf b/src/Cli/dotnet/xlf/CliStrings.es.xlf
index 932f14aad0a5..5f98b1fde756 100644
--- a/src/Cli/dotnet/xlf/CliStrings.es.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.es.xlf
@@ -102,7 +102,6 @@ Examples:
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.
Ejemplos:
@@ -373,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}
diff --git a/src/Cli/dotnet/xlf/CliStrings.fr.xlf b/src/Cli/dotnet/xlf/CliStrings.fr.xlf
index c52c236d5ae4..87f3bfc48bf6 100644
--- a/src/Cli/dotnet/xlf/CliStrings.fr.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.fr.xlf
@@ -373,6 +373,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}
diff --git a/src/Cli/dotnet/xlf/CliStrings.it.xlf b/src/Cli/dotnet/xlf/CliStrings.it.xlf
index 7e1e970856f4..c3b2156daec7 100644
--- a/src/Cli/dotnet/xlf/CliStrings.it.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.it.xlf
@@ -102,8 +102,7 @@ Examples:
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.
+È possibile specificare più volte l'argomento per fornire più variabili.
Esempi:
-e VARIABLE=abc
@@ -373,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}
diff --git a/src/Cli/dotnet/xlf/CliStrings.ja.xlf b/src/Cli/dotnet/xlf/CliStrings.ja.xlf
index 3c65a24afdd1..5c6f24e84f7d 100644
--- a/src/Cli/dotnet/xlf/CliStrings.ja.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.ja.xlf
@@ -102,7 +102,6 @@ Examples:
環境変数の値を設定します。
変数が存在しない場合は作成され、存在する場合はオーバーライドされます。
-これにより、テストは強制的に分離プロセスで実行されます。
この引数は、複数の変数を指定するために複数回指定できます。
例:
@@ -373,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 が必要です
diff --git a/src/Cli/dotnet/xlf/CliStrings.ko.xlf b/src/Cli/dotnet/xlf/CliStrings.ko.xlf
index 5e9908f47783..ce7ca80151f2 100644
--- a/src/Cli/dotnet/xlf/CliStrings.ko.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.ko.xlf
@@ -102,7 +102,6 @@ Examples:
환경 변수의 값을 설정합니다.
변수가 없는 경우 변수를 만들고, 변수가 있으면 재정의합니다.
-이는 테스트가 격리된 프로세스에서 강제로 실행되도록 합니다.
이 인수를 여러 번 지정하여 여러 변수를 제공할 수 있습니다.
예:
@@ -373,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 필요
diff --git a/src/Cli/dotnet/xlf/CliStrings.pl.xlf b/src/Cli/dotnet/xlf/CliStrings.pl.xlf
index a0827e6cca19..3b2c4a06911c 100644
--- a/src/Cli/dotnet/xlf/CliStrings.pl.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.pl.xlf
@@ -102,13 +102,12 @@ Examples:
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.
Przykłady:
-e ZMIENNA=abc
--e ZMIENNA="wartość ze spacjami"
--e ZMIENNA="wartości;rozdzielone;średnikami"
+-e ZMIENNA=”wartość ze spacjami”
+-e ZMIENNA=”wartości;rozdzielone;średnikami”
-e ZM1=abc -e ZM2=def -e ZM3=ghi
@@ -373,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}
diff --git a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf
index 1427fb9cae3c..bd45901ab4de 100644
--- a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf
@@ -373,6 +373,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}
diff --git a/src/Cli/dotnet/xlf/CliStrings.ru.xlf b/src/Cli/dotnet/xlf/CliStrings.ru.xlf
index 16d9ce2ed2a1..dfffdf7b397b 100644
--- a/src/Cli/dotnet/xlf/CliStrings.ru.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.ru.xlf
@@ -373,6 +373,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}.
diff --git a/src/Cli/dotnet/xlf/CliStrings.tr.xlf b/src/Cli/dotnet/xlf/CliStrings.tr.xlf
index 4718e0657a61..a78957418c70 100644
--- a/src/Cli/dotnet/xlf/CliStrings.tr.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.tr.xlf
@@ -102,7 +102,6 @@ Examples:
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.
Örnek:
@@ -373,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}
diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf
index 1276bb9fea39..27d5142f2243 100644
--- a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf
@@ -373,6 +373,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}
diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf
index bd73674ba27c..6fa186d5685e 100644
--- a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf
+++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf
@@ -102,7 +102,6 @@ Examples:
設定環境變數的值。
若變數不存在,則加以建立; 若有,則予以覆寫。
-這會強制在隔離流程中執行測試。
此引數可多次指定,以提供多項變數。
範例:
@@ -373,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
diff --git a/src/Layout/Directory.Build.props b/src/Layout/Directory.Build.props
index 479a7c0a421e..c8bc9ffafc2a 100644
--- a/src/Layout/Directory.Build.props
+++ b/src/Layout/Directory.Build.props
@@ -78,4 +78,10 @@
$(MSBuildThisFileDirectory)pkg\
+
+ <_RoslynAppHost Include="$(OutputPath)Roslyn\bincore\csc.dll" />
+ <_RoslynAppHost Include="$(OutputPath)Roslyn\bincore\vbc.dll" />
+ <_RoslynAppHost Include="$(OutputPath)Roslyn\bincore\VBCSCompiler.dll" />
+
+
diff --git a/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj b/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj
index bb4234adee1d..d0a01f20c9cb 100644
--- a/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj
+++ b/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/Layout/pkg/windows/bundles/sdk/LCID/1028/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1028/bundle.wxl
index f96c267482d0..96ae1777e649 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1028/bundle.wxl
+++ b/src/Layout/pkg/windows/bundles/sdk/LCID/1028/bundle.wxl
@@ -75,7 +75,7 @@
-
+
@@ -87,7 +87,7 @@
-
+
diff --git a/src/Layout/pkg/windows/bundles/sdk/LCID/1029/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1029/bundle.wxl
index cd55c114d38d..8996b6dba4d6 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1029/bundle.wxl
+++ b/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/Layout/pkg/windows/bundles/sdk/LCID/1031/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1031/bundle.wxl
index 05740b73dca1..33bf3763a241 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1031/bundle.wxl
+++ b/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/Layout/pkg/windows/bundles/sdk/LCID/1033/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1033/bundle.wxl
index 1f4adddecf7c..b3a6c66e37ca 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1033/bundle.wxl
+++ b/src/Layout/pkg/windows/bundles/sdk/LCID/1033/bundle.wxl
@@ -83,4 +83,4 @@ This product collects usage data
-
+
\ No newline at end of file
diff --git a/src/Layout/pkg/windows/bundles/sdk/LCID/1036/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1036/bundle.wxl
index 9db45ab9c73d..ca3e7b265f71 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1036/bundle.wxl
+++ b/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/Layout/pkg/windows/bundles/sdk/LCID/1040/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1040/bundle.wxl
index 69a763f2b418..aab082f8ac25 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1040/bundle.wxl
+++ b/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/Layout/pkg/windows/bundles/sdk/LCID/1041/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1041/bundle.wxl
index 666caa439253..cda559ded662 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1041/bundle.wxl
+++ b/src/Layout/pkg/windows/bundles/sdk/LCID/1041/bundle.wxl
@@ -75,7 +75,7 @@
-
+
@@ -87,7 +87,7 @@
-
+
diff --git a/src/Layout/pkg/windows/bundles/sdk/LCID/1042/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1042/bundle.wxl
index 4e66c6cfff36..754a45fe3699 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1042/bundle.wxl
+++ b/src/Layout/pkg/windows/bundles/sdk/LCID/1042/bundle.wxl
@@ -75,7 +75,7 @@
-
+
@@ -87,7 +87,7 @@
-
+
diff --git a/src/Layout/pkg/windows/bundles/sdk/LCID/1045/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1045/bundle.wxl
index 5b4721e4be71..9ab2050a67ea 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1045/bundle.wxl
+++ b/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/Layout/pkg/windows/bundles/sdk/LCID/1046/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1046/bundle.wxl
index d16c00be7ad4..f8f517f43958 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1046/bundle.wxl
+++ b/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/Layout/pkg/windows/bundles/sdk/LCID/1049/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1049/bundle.wxl
index 3e509961ce68..59c961fbdd84 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1049/bundle.wxl
+++ b/src/Layout/pkg/windows/bundles/sdk/LCID/1049/bundle.wxl
@@ -75,7 +75,7 @@
-
+
@@ -87,7 +87,7 @@
-
+
diff --git a/src/Layout/pkg/windows/bundles/sdk/LCID/1055/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/1055/bundle.wxl
index f03b83263210..0c25970fd44f 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/1055/bundle.wxl
+++ b/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/Layout/pkg/windows/bundles/sdk/LCID/2052/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/2052/bundle.wxl
index d0d5105a14dc..4b5b8b92809e 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/2052/bundle.wxl
+++ b/src/Layout/pkg/windows/bundles/sdk/LCID/2052/bundle.wxl
@@ -75,7 +75,7 @@
-
+
@@ -87,7 +87,7 @@
-
+
diff --git a/src/Layout/pkg/windows/bundles/sdk/LCID/3082/bundle.wxl b/src/Layout/pkg/windows/bundles/sdk/LCID/3082/bundle.wxl
index ec87cc1580f2..084aa9dbf0ae 100644
--- a/src/Layout/pkg/windows/bundles/sdk/LCID/3082/bundle.wxl
+++ b/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/Layout/pkg/windows/bundles/sdk/bundle.wxs b/src/Layout/pkg/windows/bundles/sdk/bundle.wxs
index f5b6a784231d..3e3724cad1ef 100644
--- a/src/Layout/pkg/windows/bundles/sdk/bundle.wxs
+++ b/src/Layout/pkg/windows/bundles/sdk/bundle.wxs
@@ -27,7 +27,13 @@
-
+
+
+
+
+
+
diff --git a/src/Layout/redist/dnx.ps1 b/src/Layout/redist/dnx.ps1
deleted file mode 100644
index ff880f85e2f6..000000000000
--- a/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/Layout/redist/targets/Crossgen.targets b/src/Layout/redist/targets/Crossgen.targets
index e9a22ddb4f8f..3e07f481af11 100644
--- a/src/Layout/redist/targets/Crossgen.targets
+++ b/src/Layout/redist/targets/Crossgen.targets
@@ -35,7 +35,6 @@
$(InstallerOutputDirectory)Sdks\Microsoft.NET.Sdk\analyzers\$(InstallerOutputDirectory)Sdks\Microsoft.NET.Sdk\tools\$(DefaultToolTfm)\$(InstallerOutputDirectory)Sdks\Microsoft.NET.Sdk.BlazorWebAssembly\tools\$(DefaultToolTfm)\
- $(InstallerOutputDirectory)Sdks\NuGet.Build.Tasks.Pack\CoreCLR\$(InstallerOutputDirectory)Sdks\Microsoft.NET.Sdk.Razor\source-generators\$(InstallerOutputDirectory)Sdks\Microsoft.NET.Sdk.Razor\tasks\$(DefaultToolTfm)\$(InstallerOutputDirectory)Sdks\Microsoft.NET.Sdk.WindowsDesktop\tools\$(DefaultToolTfm)\
@@ -74,7 +73,6 @@
-
@@ -141,7 +139,6 @@
-
@@ -200,6 +197,7 @@
+
diff --git a/src/Layout/redist/targets/GenerateInstallerLayout.targets b/src/Layout/redist/targets/GenerateInstallerLayout.targets
index 4c7aa7749e3b..069c6a2fde2a 100644
--- a/src/Layout/redist/targets/GenerateInstallerLayout.targets
+++ b/src/Layout/redist/targets/GenerateInstallerLayout.targets
@@ -67,7 +67,6 @@
-
diff --git a/src/Layout/redist/targets/GenerateLayout.targets b/src/Layout/redist/targets/GenerateLayout.targets
index 65d4aff197c6..0b5bcb6fa182 100644
--- a/src/Layout/redist/targets/GenerateLayout.targets
+++ b/src/Layout/redist/targets/GenerateLayout.targets
@@ -59,6 +59,12 @@
+
+
@@ -495,6 +501,7 @@
+
diff --git a/src/Layout/redist/targets/OverlaySdkOnLKG.targets b/src/Layout/redist/targets/OverlaySdkOnLKG.targets
index 19505de69d50..faf995466d4f 100644
--- a/src/Layout/redist/targets/OverlaySdkOnLKG.targets
+++ b/src/Layout/redist/targets/OverlaySdkOnLKG.targets
@@ -34,7 +34,7 @@
+ UseHardLinksIfPossible="false" />
fieldOrEventReferences = fieldOrEventSymbol.DeclaringSyntaxReferences;
diff --git a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers.sarif b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers.sarif
index 5c266abfe069..9be6d8f8f7d0 100644
--- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers.sarif
+++ b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers.sarif
@@ -5,7 +5,7 @@
{
"tool": {
"name": "Microsoft.CodeAnalysis.CSharp.NetAnalyzers",
- "version": "10.0.100",
+ "version": "10.0.200",
"language": "en-US"
},
"rules": {
@@ -708,7 +708,7 @@
{
"tool": {
"name": "Microsoft.CodeAnalysis.NetAnalyzers",
- "version": "10.0.100",
+ "version": "10.0.200",
"language": "en-US"
},
"rules": {
@@ -6603,7 +6603,7 @@
{
"tool": {
"name": "Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers",
- "version": "10.0.100",
+ "version": "10.0.200",
"language": "en-US"
},
"rules": {
diff --git a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureAnalyzer.cs b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureAnalyzer.cs
index 52f86e756313..1df63a6f732d 100644
--- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureAnalyzer.cs
+++ b/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/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/BasicDetectPreviewFeatureAnalyzer.vb b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/BasicDetectPreviewFeatureAnalyzer.vb
index e357049f7d52..be0214120c69 100644
--- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers/Microsoft.NetCore.Analyzers/Runtime/BasicDetectPreviewFeatureAnalyzer.vb
+++ b/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/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Analyzer.CSharp.Utilities.projitems b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Analyzer.CSharp.Utilities.projitems
index c6f9820f49f9..cad6a604c501 100644
--- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Analyzer.CSharp.Utilities.projitems
+++ b/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/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Lightup/AwaitExpressionInfoWrapper.cs b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler.CSharp/Lightup/AwaitExpressionInfoWrapper.cs
new file mode 100644
index 000000000000..719a13858a87
--- /dev/null
+++ b/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/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler/Lightup/LightupHelpers.cs b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler/Lightup/LightupHelpers.cs
index 39b63ec4ad03..8c714a20a376 100644
--- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler/Lightup/LightupHelpers.cs
+++ b/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/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureUnitTests.Misc.cs b/src/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureUnitTests.Misc.cs
index a0fe473ba9ab..b3b84fdf3516 100644
--- a/src/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Runtime/DetectPreviewFeatureUnitTests.Misc.cs
+++ b/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/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj
index de5612b1c470..20d248f368aa 100644
--- a/src/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj
+++ b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj
@@ -24,6 +24,7 @@
+
diff --git a/src/Microsoft.Net.Sdk.AnalyzerRedirecting/SdkAnalyzerAssemblyRedirector.cs b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/SdkAnalyzerAssemblyRedirector.cs
index c81a829990c2..23736deeb43e 100644
--- a/src/Microsoft.Net.Sdk.AnalyzerRedirecting/SdkAnalyzerAssemblyRedirector.cs
+++ b/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/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest
index 3c3150875aab..cfa767fb3ca0 100644
--- a/src/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest
+++ b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest
@@ -13,10 +13,10 @@
-
+
-
-
+
+ amd64
diff --git a/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs b/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs
index 6b891c586a23..ae38c8e2f61c 100644
--- a/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs
+++ b/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/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs b/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs
index 678577e9053f..a6d9f6d808ae 100644
--- a/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs
+++ b/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/Resolvers/Microsoft.DotNet.NativeWrapper/NETCoreSdkResolverNativeWrapper.cs b/src/Resolvers/Microsoft.DotNet.NativeWrapper/NETCoreSdkResolverNativeWrapper.cs
index 160346fbccfc..b0571d439d09 100644
--- a/src/Resolvers/Microsoft.DotNet.NativeWrapper/NETCoreSdkResolverNativeWrapper.cs
+++ b/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/StaticWebAssetsSdk/Tasks/GenerateStaticWebAssetEndpointsManifest.cs b/src/StaticWebAssetsSdk/Tasks/GenerateStaticWebAssetEndpointsManifest.cs
index 0387bb131057..f996a75b7168 100644
--- a/src/StaticWebAssetsSdk/Tasks/GenerateStaticWebAssetEndpointsManifest.cs
+++ b/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/StaticWebAssetsSdk/Tasks/Utils/Globbing/StaticWebAssetGlobMatcher.cs b/src/StaticWebAssetsSdk/Tasks/Utils/Globbing/StaticWebAssetGlobMatcher.cs
index 3f2910cdd1da..07b44a10440b 100644
--- a/src/StaticWebAssetsSdk/Tasks/Utils/Globbing/StaticWebAssetGlobMatcher.cs
+++ b/src/StaticWebAssetsSdk/Tasks/Utils/Globbing/StaticWebAssetGlobMatcher.cs
@@ -479,7 +479,10 @@ private static MatchStage GetInitialStage(GlobNode node)
return MatchStage.Done;
}
- internal readonly MatchState NextExtension(int extensionIndex) => new(Node, MatchStage.Extension, SegmentIndex, extensionIndex, ComplexSegmentIndex);
+ internal readonly MatchState NextExtension(int extensionIndex) => new(Node, MatchStage.Extension, SegmentIndex, extensionIndex, ComplexSegmentIndex)
+ {
+ StemStartIndex = StemStartIndex
+ };
internal readonly MatchState NextComplex() => new(Node, MatchStage.Complex, SegmentIndex, ExtensionSegmentIndex, ComplexSegmentIndex + 1);
diff --git a/src/Tasks/Common/Resources/Strings.resx b/src/Tasks/Common/Resources/Strings.resx
index 0ce5aebf5b99..518abb95d3de 100644
--- a/src/Tasks/Common/Resources/Strings.resx
+++ b/src/Tasks/Common/Resources/Strings.resx
@@ -970,10 +970,6 @@ You may need to build the project on another operating system or architecture, o
NETSDK1222: PreferNativeArm64 applies only to .NET Framework targets. It is not supported and has no effect for when targeting .NET Core.{StrBegins="NETSDK1222: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- {StrBegins="NETSDK1223: "}
-
NETSDK1224: ASP.NET Core framework assets are not supported for the target framework.{StrBegins="NETSDK1224: "}
@@ -1010,5 +1006,9 @@ You may need to build the project on another operating system or architecture, o
NETSDK1232: Unable to find a matching RID for '{0}' from among [{1}] in graph '{2}'.{StrBegins="NETSDK1232: "}{Locked="{0}"}{Locked="{1}"}{Locked="{2}"}
-
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}
+
+
diff --git a/src/Tasks/Common/Resources/xlf/Strings.cs.xlf b/src/Tasks/Common/Resources/xlf/Strings.cs.xlf
index bd159c631b08..b3150ec53b65 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.cs.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: Nativní kompilace není podporována při přímém vyvolání cíle publikování. Zkuste spustit dotnet publish.{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: Cílení na .NET 9.0 nebo vyšší se v sadě Visual Studio 2022 17.11 nepodporuje.
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: Projekt(y) několika řešení obsahuj(e/í) konfliktní hodnoty „{0}“; ujistěte se, že se hodnoty shodují. Zvažte použití souboru Directory.build.props k nastavení vlastnosti pro všechny projekty. Konfliktní projekty:
+ NETSDK1197: Projekt(y) několika řešení obsahuj(e/í) konfliktní hodnoty „{0}“; ujistěte se, že se hodnoty shodují. Zvažte použití souboru Directory.build.props k nastavení vlastnosti pro všechny projekty. Konfliktní projekty:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.de.xlf b/src/Tasks/Common/Resources/xlf/Strings.de.xlf
index 531c0faa0052..2d96be400f70 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.de.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: Die native Kompilierung wird beim direkten Aufrufen des Veröffentlichungsziels nicht unterstützt. Versuchen Sie, dotnet publish auszuführen.{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: Die Ausrichtung auf .NET 9.0 oder höher in Visual Studio 2022 17.11 wird nicht unterstützt.
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: Mehrere Projektmappenprojekte enthalten widersprüchliche Werte für "{0}". Stellen Sie sicher, dass die Werte übereinstimmen. Erwägen Sie die Verwendung einer Directory.build.props-Datei, um die Eigenschaft für alle Projekte festzulegen. In Konflikt stehende Projekte:
+ NETSDK1197: Mehrere Projektmappenprojekte enthalten widersprüchliche Werte für "{0}". Stellen Sie sicher, dass die Werte übereinstimmen. Erwägen Sie die Verwendung einer Directory.build.props-Datei, um die Eigenschaft für alle Projekte festzulegen. In Konflikt stehende Projekte:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.es.xlf b/src/Tasks/Common/Resources/xlf/Strings.es.xlf
index 511a72b3c3a6..c809c4172947 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.es.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: la compilación nativa no es compatible cuando se invoca directamente al destino al hacer "publish". Intente ejecutar dotnet publish.{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: no se admite el destino de .NET 9.0 o posterior en Visual Studio 2022 17.11.
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: Varios proyectos de solución que contienen valores '{0}' en conflicto; asegúrese de que los valores coinciden. Considere la posibilidad de usar un archivo Directory.build.props para establecer la propiedad para todos los proyectos. Proyectos en conflicto:
+ NETSDK1197: Varios proyectos de solución que contienen valores '{0}' en conflicto; asegúrese de que los valores coinciden. Considere la posibilidad de usar un archivo Directory.build.props para establecer la propiedad para todos los proyectos. Proyectos en conflicto:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.fr.xlf b/src/Tasks/Common/Resources/xlf/Strings.fr.xlf
index 9c62ece01900..4f8f47200d1c 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.fr.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: la compilation native n’est pas prise en charge lors de l’appel direct de la cible de publication. Essayez d’exécuter dotnet publish.{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: Le ciblage de .NET 9.0 ou version ultérieure dans Visual Studio 2022 17.11 n’est pas pris en charge.
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: plusieurs projets de solution contiennent des valeurs '{0}' en conflit ; assurez-vous que les valeurs correspondent. Envisagez d'utiliser un fichier Directory.build.props pour définir la propriété pour tous les projets. Projets conflictuels :
+ NETSDK1197: plusieurs projets de solution contiennent des valeurs '{0}' en conflit ; assurez-vous que les valeurs correspondent. Envisagez d'utiliser un fichier Directory.build.props pour définir la propriété pour tous les projets. Projets conflictuels :
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.it.xlf b/src/Tasks/Common/Resources/xlf/Strings.it.xlf
index de06e93873ab..6f47775c6a67 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.it.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: la compilazione nativa non è supportata quando si richiama direttamente la destinazione di pubblicazione. Provare a eseguire dotnet publish.{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: la destinazione .NET 9.0 o versione successiva in Visual Studio 2022 17.11 non è supportata.
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: più progetti della soluzione contengono valori '{0}' in conflitto. Verificare che i valori corrispondano. Provare a usare un file Directory.build.props per impostare la proprietà di tutti i progetti. Progetti in conflitto:
+ NETSDK1197: più progetti della soluzione contengono valori '{0}' in conflitto. Verificare che i valori corrispondano. Provare a usare un file Directory.build.props per impostare la proprietà di tutti i progetti. Progetti in conflitto:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.ja.xlf b/src/Tasks/Common/Resources/xlf/Strings.ja.xlf
index babd059b78b5..03fb4261129c 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.ja.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: Publish ターゲットを直接呼び出す場合、ネイティブ コンパイルはサポートされません。dotnet publish を実行してみてください。{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: Visual Studio 2022 17.11 では .NET 9.0 以上をターゲットにすることはできません。
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: 複数のソリューションのプロジェクトに、競合する '{0}' 値が含まれています。値が一致するようにしてください。Directory.build.props ファイルを使用して、すべてのプロジェクトのプロパティを設定することを検討してください。競合するプロジェクト:
+ NETSDK1197: 複数のソリューションのプロジェクトに、競合する '{0}' 値が含まれています。値が一致するようにしてください。Directory.build.props ファイルを使用して、すべてのプロジェクトのプロパティを設定することを検討してください。競合するプロジェクト:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.ko.xlf b/src/Tasks/Common/Resources/xlf/Strings.ko.xlf
index 36b7099e3bdf..367083c96234 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.ko.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: 게시 대상을 직접 호출할 때는 네이티브 컴파일이 지원되지 않습니다. dotnet publish를 실행해 보세요.{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: Visual Studio 2022 17.11에서 .NET 9.0 이상을 대상으로 지정하는 것은 지원되지 않습니다.
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: 여러 솔루션 프로젝트에 충돌하는 '{0}' 값이 있습니다. 값이 일치하는지 확인하세요. Directory.build.props 파일을 사용하여 모든 프로젝트에 대한 속성을 설정하는 것이 좋습니다. 충돌하는 프로젝트:
+ NETSDK1197: 여러 솔루션 프로젝트에 충돌하는 '{0}' 값이 있습니다. 값이 일치하는지 확인하세요. Directory.build.props 파일을 사용하여 모든 프로젝트에 대한 속성을 설정하는 것이 좋습니다. 충돌하는 프로젝트:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.pl.xlf b/src/Tasks/Common/Resources/xlf/Strings.pl.xlf
index dc4aba1f2e5e..9ae273652d32 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.pl.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: kompilacja natywna nie jest obsługiwana podczas bezpośredniego wywoływania obiektu docelowego publikowania. Spróbuj uruchomić polecenie dotnet publish.{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: platforma docelowa .NET 9.0 lub nowsza w programie Visual Studio 2022 17.11 nie jest obsługiwana.
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: Wiele projektów rozwiązań zawiera wartości „{0}” powodujące konflikt; upewnij się, że wartości są zgodne. Rozważ użycie pliku Directory.build.props na potrzeby ustawienia właściwości dla wszystkich projektów. Projekty powodujące konflikt:
+ NETSDK1197: Wiele projektów rozwiązań zawiera wartości „{0}” powodujące konflikt; upewnij się, że wartości są zgodne. Rozważ użycie pliku Directory.build.props na potrzeby ustawienia właściwości dla wszystkich projektów. Projekty powodujące konflikt:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf b/src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf
index 906080a716bd..e5dd12698ed0 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: não há suporte para a compilação nativa ao invocar o destino Publicar diretamente. Tente executar dotnet publish.{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: não há suporte para o direcionamento do .NET 9.0 ou superior no Visual Studio 2022 17.11.
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: Vários projetos de solução contêm valores '{0}' conflitantes; garantir que os valores correspondam. Considere usar um arquivo Directory.build.props para configurar a propriedade para todos os projetos. Projetos conflitantes:
+ NETSDK1197: Vários projetos de solução contêm valores '{0}' conflitantes; garantir que os valores correspondam. Considere usar um arquivo Directory.build.props para configurar a propriedade para todos os projetos. Projetos conflitantes:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.ru.xlf b/src/Tasks/Common/Resources/xlf/Strings.ru.xlf
index 135d04e004a0..80990c05eb42 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.ru.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: компиляция собственного кода не поддерживается при прямом вызове целевого объекта публикации. Попробуйте запустить dotnet publish.{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: Нацеливание на .NET 9.0 или более поздней версии в Visual Studio 2022 17.11 не поддерживается.
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: несколько проектов решения содержат конфликтующие значения "{0}". Убедитесь, что значения совпадают. Рассмотрите возможность использования файла Directory.build.props для настройки свойства для всех проектов. Конфликтующие проекты:
+ NETSDK1197: несколько проектов решения содержат конфликтующие значения "{0}". Убедитесь, что значения совпадают. Рассмотрите возможность использования файла Directory.build.props для настройки свойства для всех проектов. Конфликтующие проекты:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.tr.xlf b/src/Tasks/Common/Resources/xlf/Strings.tr.xlf
index ddf897db38c3..3d5a18e84483 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.tr.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: Yayımlama hedefi doğrudan çağrıldığında yerel derleme desteklenmez. dotnet publish komutunu çalıştırmayı deneyin.{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: Visual Studio 2022 17.11'de .NET 9.0 veya daha üst sürümünü hedefleme desteklenmiyor.
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: Birden çok çözüm projesi çakışan '{0}' değerleri içeriyor; değerlerin eşleştiğinden emin olun. Özelliği tüm projeler için ayarlamak için Directory.build.props dosyası kullanabilirsiniz. Çakışan projeler:
+ NETSDK1197: Birden çok çözüm projesi çakışan '{0}' değerleri içeriyor; değerlerin eşleştiğinden emin olun. Özelliği tüm projeler için ayarlamak için Directory.build.props dosyası kullanabilirsiniz. Çakışan projeler:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf b/src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf
index 3ab48490f99b..4724120c66ed 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: 直接调用发布目标时不支持本机编译。尝试运行 dotnet publish。{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: 不支持在 Visual Studio 2022 17.11 中以 .NET 9.0 或更高版本为目标。
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: 多个解决方案项目包含存在冲突的“{0}”值;请确保值能够匹配。请考虑使用 Directory.build.props 文件设置所有项目的属性。存在冲突的项目:
+ NETSDK1197: 多个解决方案项目包含存在冲突的“{0}”值;请确保值能够匹配。请考虑使用 Directory.build.props 文件设置所有项目的属性。存在冲突的项目:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf b/src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf
index 10ec0f90c63c..9d8d0bf09817 100644
--- a/src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf
+++ b/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: "}
@@ -661,10 +661,10 @@ The following are names of parameters or literal values and should not be transl
NETSDK1225: 直接叫用 [發佈] 目標時,不支援原生編譯。請嘗試執行 dotnet publish。{StrBegins="NETSDK1225: "}
-
- NETSDK1223: Targeting .NET 9.0 or higher in Visual Studio 2022 17.11 is not supported.
- NETSDK1223: 不支援在 Visual Studio 2022 17.11 中以 .NET 9.0 或更高版本為目標。
- {StrBegins="NETSDK1223: "}
+
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ NETSDK1233: Targeting .NET 10.0 or higher in Visual Studio 2022 17.14 is not supported.
+ {StrBegins="NETSDK1233: "}NETSDK1084: There is no application host available for the specified RuntimeIdentifier '{0}'.
@@ -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}"}
@@ -914,7 +914,7 @@ The following are names of parameters or literal values and should not be transl
NETSDK1197: Multiple solution project(s) contain conflicting '{0}' values; ensure the values match. Consider using a Directory.build.props file to set the property for all projects. Conflicting projects:
{1}
- NETSDK1197: 多個解決方案專案包含衝突的 '{0}' 值; 請確保值相符。考慮使用 Directory.build.props 檔案來設定所有專案的屬性。衝突的專案:
+ NETSDK1197: 多個解決方案專案包含衝突的 '{0}' 值; 請確保值相符。考慮使用 Directory.build.props 檔案來設定所有專案的屬性。衝突的專案:
{1}{StrBegins="NETSDK1197: "}
@@ -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/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenThatWeHaveErrorCodes.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenThatWeHaveErrorCodes.cs
index 51b35793ffa5..dc383cfdeaa0 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenThatWeHaveErrorCodes.cs
+++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenThatWeHaveErrorCodes.cs
@@ -40,7 +40,8 @@ public class GivenThatWeHaveErrorCodes
1192,
1213,
1214,
- 1219
+ 1219,
+ 1223
};
//ILLink lives in other repos and violated the _info requirement for no error code
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj b/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj
index 157fde746f9d..d32804d3ee51 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj
+++ b/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj
@@ -56,7 +56,8 @@
-
+
+
@@ -131,17 +132,12 @@
- <_NugetBuildTasksPackPath>$(NuGetPackageRoot)nuget.build.tasks.pack\$(NuGetBuildTasksPackageVersion)
<_Stage0SdksFolder>$(DOTNET_INSTALL_DIR)\sdk\$(NETCoreSdkVersion)\Sdks
%(None.PackagePath)\%(None.RecursiveDir)%(None.Filename)%(None.Extension)
-
-
- ..\NuGet.Build.Tasks.Pack\%(PackFile.RecursiveDir)%(PackFile.Filename)%(PackFile.Extension)
-
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs
index 191dbdaeee48..a119f005fe80 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs
+++ b/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs
@@ -817,20 +817,36 @@ private ToolPackSupport AddToolPack(
{
var packNamePattern = knownPack.GetMetadata(packName + "PackNamePattern");
var packSupportedRuntimeIdentifiers = knownPack.GetMetadata(packName + "RuntimeIdentifiers").Split(';');
- // When publishing for the non-portable RID that matches NETCoreSdkRuntimeIdentifier, prefer NETCoreSdkRuntimeIdentifier for the host.
+ var packSupportedPortableRuntimeIdentifiers = knownPack.GetMetadata(packName + "PortableRuntimeIdentifiers").Split(';');
+
+ // When publishing for a non-portable RID, prefer NETCoreSdkRuntimeIdentifier for the host.
// Otherwise prefer the NETCoreSdkPortableRuntimeIdentifier.
- // This makes non-portable SDKs behave the same as portable SDKs except for the specific case of targetting the non-portable RID.
- // It also enables the non-portable ILCompiler to be packaged separately from the SDK and
- // only required when publishing for the non-portable SDK RID.
- string portableSdkRid = !string.IsNullOrEmpty(NETCoreSdkPortableRuntimeIdentifier) ? NETCoreSdkPortableRuntimeIdentifier : NETCoreSdkRuntimeIdentifier;
- bool targetsNonPortableSdkRid = EffectiveRuntimeIdentifier == NETCoreSdkRuntimeIdentifier && NETCoreSdkRuntimeIdentifier != portableSdkRid;
- string? hostRuntimeIdentifier = targetsNonPortableSdkRid ? NETCoreSdkRuntimeIdentifier : portableSdkRid;
- Log.LogMessage(MessageImportance.Low, $"Determining best RID for '{knownPack.ItemSpec}@{packVersion}' for '{hostRuntimeIdentifier}' from among '{knownPack.GetMetadata(packName + "RuntimeIdentifiers")}'");
- // Get the best RID for the host machine, which will be used to validate that we can run crossgen for the target platform and architecture
+ // This makes non-portable SDKs behave the same as portable SDKs except for the specific case of targetting a non-portable RID.
+ // This ensures that targeting portable RIDs doesn't require any non-portable assets that aren't packaged in the SDK.
+ // Due to size concerns, the non-portable ILCompiler and Crossgen2 aren't included by default in non-portable SDK distributions.
var runtimeGraph = new RuntimeGraphCache(this).GetRuntimeGraph(RuntimeGraphPath);
- hostRuntimeIdentifier = NuGetUtils.GetBestMatchingRid(runtimeGraph, hostRuntimeIdentifier, packSupportedRuntimeIdentifiers, out bool wasInGraph);
+
+ // Prefer portable when the "supported RID" for the tool pack is the same RID as the "supported portable RID".
+ // This makes non-portable SDKs behave the same as portable SDKs except for the specific cases added to "supported", such as targeting the non-portable RID.
+ // This also ensures that targeting common RIDs doesn't require any non-portable assets that aren't packaged in the SDK by default.
+ // Due to size concerns, the non-portable ILCompiler and Crossgen2 aren't included by default in non-portable SDK distributions.
+ var runtimeIdentifier = RuntimeIdentifier ?? "any";
+ string? supportedTargetRid = NuGetUtils.GetBestMatchingRid(runtimeGraph, runtimeIdentifier, packSupportedRuntimeIdentifiers, out _);
+ string? supportedPortableTargetRid = NuGetUtils.GetBestMatchingRid(runtimeGraph, runtimeIdentifier, packSupportedPortableRuntimeIdentifiers, out _);
+
+ bool usePortable = !string.IsNullOrEmpty(NETCoreSdkPortableRuntimeIdentifier)
+ && supportedTargetRid is not null && supportedPortableTargetRid is not null
+ && supportedTargetRid == supportedPortableTargetRid;
+
+ // Get the best RID for the host machine, which will be used to validate that we can run crossgen for the target platform and architecture
+ Log.LogMessage(MessageImportance.Low, $"Determining best RID for '{knownPack.ItemSpec}@{packVersion}' from among '{knownPack.GetMetadata(packName + "RuntimeIdentifiers")}'");
+ string? hostRuntimeIdentifier = usePortable
+ ? NuGetUtils.GetBestMatchingRid(runtimeGraph, NETCoreSdkPortableRuntimeIdentifier!, packSupportedPortableRuntimeIdentifiers, out _)
+ : NuGetUtils.GetBestMatchingRid(runtimeGraph, NETCoreSdkRuntimeIdentifier!, packSupportedRuntimeIdentifiers, out _);
+
if (hostRuntimeIdentifier == null)
{
+ Log.LogMessage(MessageImportance.Low, $"No matching RID was found'");
return ToolPackSupport.UnsupportedForHostRuntimeIdentifier;
}
Log.LogMessage(MessageImportance.Low, $"Best RID for '{knownPack.ItemSpec}@{packVersion}' is '{hostRuntimeIdentifier}'");
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/sdk/Sdk.targets b/src/Tasks/Microsoft.NET.Build.Tasks/sdk/Sdk.targets
index 841a3654e9ea..3c8ce290c016 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/sdk/Sdk.targets
+++ b/src/Tasks/Microsoft.NET.Build.Tasks/sdk/Sdk.targets
@@ -46,8 +46,7 @@ Copyright (c) .NET Foundation. All rights reserved.
- $(MSBuildThisFileDirectory)..\..\NuGet.Build.Tasks.Pack\buildCrossTargeting\NuGet.Build.Tasks.Pack.targets
- $(MSBuildThisFileDirectory)..\..\NuGet.Build.Tasks.Pack\build\NuGet.Build.Tasks.Pack.targets
+ $(MSBuildThisFileDirectory)..\..\..\NuGet.Build.Tasks.Pack.targetstrue
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets
index 6566bebb20ef..0ac75dd8f8ae 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets
+++ b/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
+
+
-
+ Condition="$([MSBuild]::VersionLessThan($(MSBuildVersion), '17.15.0')) and '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(_TargetFrameworkVersionWithoutV), '10.0'))">
+
+
+
+ <_ImplicitFileBasedProgramUserSecretsId Condition="'$(FileBasedProgram)' == 'true'">$(MSBuildProjectName)-$([MSBuild]::StableStringHash($(MSBuildProjectFullPath.ToLowerInvariant()), 'Sha256'))
+ $(_ImplicitFileBasedProgramUserSecretsId)
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.TargetFrameworkInference.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.TargetFrameworkInference.targets
index 2eb7b93b4e92..7e902d066b81 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.TargetFrameworkInference.targets
+++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.TargetFrameworkInference.targets
@@ -54,7 +54,7 @@ Copyright (c) .NET Foundation. All rights reserved.
$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)'))v$([MSBuild]::GetTargetFrameworkVersion('$(TargetFramework)', 2))
-
+
<_TargetFrameworkVersionWithoutV>$(TargetFrameworkVersion.TrimStart('vV'))
@@ -154,8 +154,8 @@ Copyright (c) .NET Foundation. All rights reserved.
-
-
+
+
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.WindowsSdkSupportedTargetPlatforms.props b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.WindowsSdkSupportedTargetPlatforms.props
index 0a33b09d81f8..3062e1d926b5 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.WindowsSdkSupportedTargetPlatforms.props
+++ b/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/Tasks/sdk-tasks/GenerateRuntimeAnalyzersSWR.cs b/src/Tasks/sdk-tasks/GenerateRuntimeAnalyzersSWR.cs
index f899342e578e..fd5d0e6370ba 100644
--- a/src/Tasks/sdk-tasks/GenerateRuntimeAnalyzersSWR.cs
+++ b/src/Tasks/sdk-tasks/GenerateRuntimeAnalyzersSWR.cs
@@ -19,11 +19,19 @@ public override bool Execute()
// NOTE: Keep in sync with SdkAnalyzerAssemblyRedirector.
// This is intentionally short to avoid long path problems.
- const string installDir = @"DotNetRuntimeAnalyzers";
+ const string installDir = @"Common7\IDE\CommonExtensions\Microsoft\DotNet";
AddFolder(sb,
- @"AnalyzerRedirecting",
- @"Common7\IDE\CommonExtensions\Microsoft\AnalyzerRedirecting",
+ "",
+ installDir,
+ filesToInclude:
+ [
+ "metadata.json",
+ ]);
+
+ AddFolder(sb,
+ "AnalyzerRedirecting",
+ @$"{installDir}\AnalyzerRedirecting",
filesToInclude:
[
"Microsoft.Net.Sdk.AnalyzerRedirecting.dll",
@@ -32,23 +40,23 @@ public override bool Execute()
]);
AddFolder(sb,
- @"AspNetCoreAnalyzers",
+ "AspNetCoreAnalyzers",
@$"{installDir}\AspNetCoreAnalyzers");
AddFolder(sb,
- @"NetCoreAnalyzers",
+ "NetCoreAnalyzers",
@$"{installDir}\NetCoreAnalyzers");
AddFolder(sb,
- @"WindowsDesktopAnalyzers",
+ "WindowsDesktopAnalyzers",
@$"{installDir}\WindowsDesktopAnalyzers");
AddFolder(sb,
- @"SDKAnalyzers",
+ "SDKAnalyzers",
@$"{installDir}\SDKAnalyzers");
AddFolder(sb,
- @"WebSDKAnalyzers",
+ "WebSDKAnalyzers",
@$"{installDir}\WebSDKAnalyzers");
File.WriteAllText(OutputFile, sb.ToString());
diff --git a/src/Tasks/sdk-tasks/ProcessRuntimeAnalyzerVersions.cs b/src/Tasks/sdk-tasks/ProcessRuntimeAnalyzerVersions.cs
new file mode 100644
index 000000000000..e1f7df9dd671
--- /dev/null
+++ b/src/Tasks/sdk-tasks/ProcessRuntimeAnalyzerVersions.cs
@@ -0,0 +1,58 @@
+// 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.Build.Tasks;
+
+///
+/// Extracts version numbers and saves them into a metadata file.
+///
+public sealed class ProcessRuntimeAnalyzerVersions : Task
+{
+ [Required]
+ public ITaskItem[]? Inputs { get; set; }
+
+ [Required]
+ public string? MetadataFilePath { get; set; }
+
+ [Output]
+ public ITaskItem[]? Outputs { get; set; }
+
+ public override bool Execute()
+ {
+ var metadata = new Dictionary();
+
+ // Extract version from a path like:
+ // ...\packs\Microsoft.NetCore.App.Ref\\analyzers\**\*.*
+ // The version segment is always the first segment in %(RecursiveDir).
+ foreach (var input in Inputs ?? [])
+ {
+ var deploymentSubpath = input.GetMetadata("DeploymentSubpath");
+ var recursiveDir = input.GetMetadata("CustomRecursiveDir");
+
+ var slashIndex = recursiveDir.IndexOfAny('/', '\\');
+ var version = recursiveDir.Substring(0, slashIndex);
+ var rest = recursiveDir.Substring(slashIndex + 1);
+
+ input.SetMetadata("CustomRecursiveDir", rest);
+
+ if (!metadata.TryGetValue(deploymentSubpath, out var existingVersion))
+ {
+ metadata.Add(deploymentSubpath, version);
+ }
+ else if (existingVersion != version)
+ {
+ Log.LogError($"Version mismatch for '{deploymentSubpath}': '{existingVersion}' != '{version}'. " +
+ $"Expected only one version of '{input.GetMetadata("Identity")}'.");
+ return false;
+ }
+ }
+
+ Directory.CreateDirectory(Path.GetDirectoryName(MetadataFilePath)!);
+ File.WriteAllText(path: MetadataFilePath!, JsonSerializer.Serialize(metadata));
+
+ Outputs = Inputs;
+ return true;
+ }
+}
diff --git a/src/Tasks/sdk-tasks/sdk-tasks.InTree.targets b/src/Tasks/sdk-tasks/sdk-tasks.InTree.targets
index 0ab2824f1c38..547f8ccd7595 100644
--- a/src/Tasks/sdk-tasks/sdk-tasks.InTree.targets
+++ b/src/Tasks/sdk-tasks/sdk-tasks.InTree.targets
@@ -27,6 +27,7 @@
+
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.cs.json
index 78c8287035f0..055a31846996 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.cs.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.cs.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "Nejnovější hlavní verze",
"symbols/RollForward/choices/disable/description": "Nedá se posunout vpřed. Vyžaduje se přesná shoda.",
"symbols/RollForward/choices/disable/displayName": "Zakázat posunutí vpřed",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "Spouštěč testů, který se má použít.",
+ "symbols/TestRunner/displayName": "Test Runner",
+ "symbols/TestRunner/choices/VSTest/description": "Použít VSTest jako spouštěč testů",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Použít Microsoft.Testing.Platform jako spouštěč testů",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "Otevře global.json v editoru."
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.de.json
index 3b9e4c415693..6157073e542e 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.de.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.de.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "Neueste Haupt-",
"symbols/RollForward/choices/disable/description": "Kein Rollforward. Exakte Übereinstimmung erforderlich.",
"symbols/RollForward/choices/disable/displayName": "Rollforward deaktivieren",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "Der zu verwendende Testausführer.",
+ "symbols/TestRunner/displayName": "Test Runner",
+ "symbols/TestRunner/choices/VSTest/description": "VSTest als Testausführer verwenden",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Microsoft.Testing.Platform als Testausführer verwenden",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "Öffnet „global.json“ im Editor."
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.es.json
index 91b84990cc56..289585b96176 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.es.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.es.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "Última versión principal",
"symbols/RollForward/choices/disable/description": "No se hace un reenvío. Se requiere una coincidencia exacta.",
"symbols/RollForward/choices/disable/displayName": "Deshabilitar el reenvío",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "Ejecutor de pruebas que se va a usar.",
+ "symbols/TestRunner/displayName": "Ejecutor de pruebas",
+ "symbols/TestRunner/choices/VSTest/description": "Usar VSTest como ejecutor de pruebas",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Usar Microsoft.Testing.Platform como ejecutor de pruebas",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "Abre global.json el editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.fr.json
index 6a0d8074ddec..28f116ff68b3 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.fr.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.fr.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "Dernière version majeure",
"symbols/RollForward/choices/disable/description": "Ne pas restaurer par progression vers l’avant. Correspondance exacte requise.",
"symbols/RollForward/choices/disable/displayName": "Désactiver la restauration par progression",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "Le moteur de test à utiliser.",
+ "symbols/TestRunner/displayName": "Test Runner",
+ "symbols/TestRunner/choices/VSTest/description": "Utilisez VSTest comme moteur de test",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Utiliser Microsoft.Testing.Platform comme moteur de test",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "Ouvre global.json dans l’éditeur"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.it.json
index 1955f5986f6b..2a62d6bc5c55 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.it.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.it.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "Valore principale più recente",
"symbols/RollForward/choices/disable/description": "Non esegue il roll-forward. Corrispondenza esatta richiesta.",
"symbols/RollForward/choices/disable/displayName": "Disabilita roll-forward",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "Test runner da usare.",
+ "symbols/TestRunner/displayName": "Test Runner",
+ "symbols/TestRunner/choices/VSTest/description": "Usa VSTest come test runner",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Usa Microsoft.Testing.Platform come test runner",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "Apre global.json nell'editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ja.json
index dd3c5bfae900..35c290f8b8fd 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ja.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ja.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "最新のメジャー",
"symbols/RollForward/choices/disable/description": "ロールフォワードしません。完全に一致する必要があります。",
"symbols/RollForward/choices/disable/displayName": "ロールフォワードの無効化",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "使用するテスト ランナーです。",
+ "symbols/TestRunner/displayName": "Test Runner",
+ "symbols/TestRunner/choices/VSTest/description": "VSTest をテスト ランナーとして使用する",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Microsoft.Testing.Platform をテスト ランナーとして使用する",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "エディターで global.json を開く"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ko.json
index 63603d9e76c0..79c43a896860 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ko.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ko.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "최신 주",
"symbols/RollForward/choices/disable/description": "롤포워드하지 않습니다. 정확히 일치해야 합니다.",
"symbols/RollForward/choices/disable/displayName": "롤포워드 비활성화",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "사용할 Test Runner입니다.",
+ "symbols/TestRunner/displayName": "Test Runner",
+ "symbols/TestRunner/choices/VSTest/description": "VSTest를 Test Runner로 사용",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Microsoft.Testing.Platform을 Test Runner로 사용",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "편집기에서 global.json을 엽니다"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.pl.json
index 52731300fa71..a7239081f6e8 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.pl.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.pl.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "Najnowszy przedział główny",
"symbols/RollForward/choices/disable/description": "Nie przechodzi. Wymagane jest dokładne dopasowanie.",
"symbols/RollForward/choices/disable/displayName": "Wyłącz przechodzenie",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "Moduł uruchamiający testy do użycia.",
+ "symbols/TestRunner/displayName": "Moduł uruchamiający",
+ "symbols/TestRunner/choices/VSTest/description": "Używa narzędzia VSTest jako modułu uruchamiającego testy",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Użyj elementu Microsoft.Testing.Platform jako modułu uruchamiającego testy",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "Otwiera plik global.json w edytorze"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.pt-BR.json
index 5ac94d837da2..55a2663ecced 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.pt-BR.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.pt-BR.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "Principal mais recente",
"symbols/RollForward/choices/disable/description": "Não rola para frente. Correspondência exata necessária.",
"symbols/RollForward/choices/disable/displayName": "Desabilitar rolar para frente",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "O executor de teste a ser usado.",
+ "symbols/TestRunner/displayName": "Executor de teste",
+ "symbols/TestRunner/choices/VSTest/description": "Usar VSTest como executor de teste",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Usar Microsoft.Testing.Platform como executor de teste",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "Abrir global.json no editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ru.json
index fea09bc51165..a07f42658c92 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ru.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.ru.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "Последняя основная версия",
"symbols/RollForward/choices/disable/description": "Накат не выполняется. Требуется точное совпадение.",
"symbols/RollForward/choices/disable/displayName": "Отключить накат",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "Средство выполнения тестов для использования.",
+ "symbols/TestRunner/displayName": "Средство выполнения тестов",
+ "symbols/TestRunner/choices/VSTest/description": "Использовать VSTest в качестве средства выполнения тестов",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Использовать Microsoft.Testing.Platform в качестве средства выполнения тестов",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "Открывает файл global.json в редакторе"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.tr.json
index 4ccff9c7d878..74048234a66c 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.tr.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.tr.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "Son birincil sürüm",
"symbols/RollForward/choices/disable/description": "İleri sarılmıyor. Tam eşleşme gerekiyor.",
"symbols/RollForward/choices/disable/displayName": "İleri sarma devre dışı bırakıldı",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "Kullanılacak test çalıştırıcısı.",
+ "symbols/TestRunner/displayName": "Test çalıştırıcı",
+ "symbols/TestRunner/choices/VSTest/description": "Test çalıştırıcısı olarak VSTest'i kullanın",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Test çalıştırıcı olarak Microsoft.Testing.Platform'u kullanın",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "Düzenleyicide global.json dosyasını açar"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.zh-Hans.json
index cd4c9cb8e84f..5030c3598283 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.zh-Hans.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.zh-Hans.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "最新主要版本",
"symbols/RollForward/choices/disable/description": "不要前滚。需要完全匹配。",
"symbols/RollForward/choices/disable/displayName": "禁用前滚",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "要使用的测试运行程序。",
+ "symbols/TestRunner/displayName": "Test Runner",
+ "symbols/TestRunner/choices/VSTest/description": "使用 VSTest 作为测试运行程序",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "使用 Microsoft.Testing.Platform 作为测试运行程序",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "在编辑器中打开 global.json"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.zh-Hant.json
index 169fa5fd8f29..a459d69f8807 100644
--- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.zh-Hant.json
+++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/GlobalJson/.template.config/localize/templatestrings.zh-Hant.json
@@ -25,11 +25,11 @@
"symbols/RollForward/choices/latestMajor/displayName": "最新主要",
"symbols/RollForward/choices/disable/description": "不向前復原。需要完全相符。",
"symbols/RollForward/choices/disable/displayName": "停用向前復原",
- "symbols/TestRunner/description": "The test runner to use.",
- "symbols/TestRunner/displayName": "Test runner",
- "symbols/TestRunner/choices/VSTest/description": "Use VSTest as test runner",
+ "symbols/TestRunner/description": "要使用的測試執行器。",
+ "symbols/TestRunner/displayName": "測試執行器",
+ "symbols/TestRunner/choices/VSTest/description": "使用 VSTest 作為測試執行器",
"symbols/TestRunner/choices/VSTest/displayName": "VSTest",
- "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform as test runner",
+ "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "使用 Microsoft.Testing.Platform 測試執行器",
"symbols/TestRunner/choices/Microsoft.Testing.Platform/displayName": "Microsoft.Testing.Platform",
"postActions/open-file/description": "在編輯器中開啟 global.json"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.cs.json
index a84a213c397a..dbdc72f5048d 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.cs.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.cs.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Metoda testovacího přípravku TestCleanup",
"postActions/restoreNugetPackages/description": "Obnoví balíčky NuGet vyžadované tímto projektem.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Spustit dotnet restore",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Vytvořte nebo aktualizujte soubor global.json vyžadovaný Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Ručně aktualizujte nebo vytvořte soubor global.json, který nastaví spouštěč testů na Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Otevře Test1.cs v editoru."
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.de.json
index 6ce2fa04d6bb..827485d01a68 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.de.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.de.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Fixierungsmethode \"TestCleanup\"",
"postActions/restoreNugetPackages/description": "Stellt die NuGet-Pakete wieder her, die für dieses Projekt erforderlich sind.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "\"dotnet restore\" ausführen",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Erstellen oder aktualisieren Sie die für die Microsoft.Testing.Platform erforderliche Datei „global.json“.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Aktualisieren oder erstellen Sie die Datei „global.json“ manuell, um den Testausführer auf Microsoft.Testing.Platform einzustellen.",
"postActions/openInEditor/description": "Öffnet Test1.cs im Editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.es.json
index 79f6e8b7ed5f..c35eccac0856 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.es.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.es.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Método de accesorio TestCleanup",
"postActions/restoreNugetPackages/description": "Restaure los paquetes NuGet necesarios para este proyecto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Ejecutar \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Cree o actualice el archivo \"global.json\" requerido por Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Actualizar o crear manualmente el archivo \"global.json\" estableciendo el ejecutor de pruebas en Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Abrir Test1.cs en el editor."
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.fr.json
index 53fe20ff3650..33a3f59420f6 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.fr.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.fr.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Méthode de fixture TestCleanup",
"postActions/restoreNugetPackages/description": "Restaurez les packages NuGet requis par ce projet.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Exécutez « dotnet restore »",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Créez ou mettez à jour le fichier « global.json » requis par Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Mettez à jour ou créez manuellement le fichier « global.json » en définissant l’exécuteur de tests sur Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Ouvre Test1.cs dans l’éditeur"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.it.json
index f0bbe81b6081..385d5e56fdb7 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.it.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.it.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Metodo fixture TestCleanup",
"postActions/restoreNugetPackages/description": "Ripristina i pacchetti NuGet richiesti da questo progetto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Esegui 'dotnet restore'",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Creare o aggiornare il file 'global.json' richiesto da Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Aggiornare o creare manualmente il file 'global.json' impostando il test runner su Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Apre Test1.cs nell'editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ja.json
index 8abec526fba5..5e9ca4b3ba89 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ja.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ja.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup フィクスチャ メソッド",
"postActions/restoreNugetPackages/description": "このプロジェクトに必要な NuGet パッケージを復元します。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "'dotnet restore' を実行する",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform に必要な 'global.json' ファイルを作成または更新します。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "テスト ランナーを Microsoft.Testing.Platform に設定する 'global.json' ファイルを手動で更新または作成する",
"postActions/openInEditor/description": "エディターで Test1.cs を開きます"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ko.json
index 7b5233ccbc18..a0c1a01a2d67 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ko.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ko.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup fixture 메서드",
"postActions/restoreNugetPackages/description": "이 프로젝트에 필요한 NuGet 패키지를 복원합니다.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "'dotnet restore' 실행",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform에 필요한 'global.json' 파일을 만들거나 업데이트합니다.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "테스트 실행기를 Microsoft.Testing.Platform으로 설정하는 'global.json' 파일을 수동으로 만들거나 업데이트합니다.",
"postActions/openInEditor/description": "편집기에서 Test1.cs 열기"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pl.json
index bca7305e53d9..5bda1965559b 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pl.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pl.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup — metoda początkowa",
"postActions/restoreNugetPackages/description": "Przywróć pakiety NuGet wymagane przez ten projekt.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Uruchom polecenie „dotnet restore”",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Utwórz lub zaktualizuj plik „global.json” wymagany przez Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Ręcznie zaktualizuj lub utwórz plik „global.json” ustawiając moduł uruchamiający testy na Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Otwiera plik Test1.cs w edytorze"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json
index e97e6205db55..a14db3f6cfe2 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Método de acessório TestCleanup",
"postActions/restoreNugetPackages/description": "Restaura os pacotes do NuGet exigidos por este projeto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Executa \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Criar ou atualizar o arquivo 'global.json' necessário para o Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Atualize ou crie manualmente o arquivo 'global.json', definindo o test runner como Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Abre o Test1.cs no editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ru.json
index b3bd988269a7..e677a9bfed40 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ru.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ru.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Метод работы со средствами TestCleanup",
"postActions/restoreNugetPackages/description": "Восстановление пакетов NuGet, необходимых для этого проекта.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Выполнить команду \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Создайте или обновите файл global.json, необходимый для Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Вручную обновите или создайте файл global.json, настраивающий Microsoft.Testing.Platform в качестве средства выполнения тестов",
"postActions/openInEditor/description": "Открывает Test1.cs редакторе"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.tr.json
index e09e1d1eb151..c2710ec296de 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.tr.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.tr.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup düzen yöntemi",
"postActions/restoreNugetPackages/description": "Bu projenin gerektirdiği NuGet paketlerini geri yükleyin.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "\"dotnet restore\" çalıştır",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform tarafından gerekli olan ‘global.json’ dosyasını oluşturun veya güncelleştirin.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Test çalıştırıcısını Microsoft.Testing.Platform olarak ayarlayarak ‘global.json’ dosyasını manuel olarak güncelleştirin veya oluşturun.",
"postActions/openInEditor/description": "Test1.cs'yi düzenleyicide açar"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json
index a7fda34f2294..8a8bbfb8339c 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup 固定例程方法",
"postActions/restoreNugetPackages/description": "还原此项目所需的 NuGet 包。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "运行 \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "创建或更新 Microsoft.Testing.Platform 所需的 \"global.json\" 文件。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "手动更新或创建 \"global.json\" 文件,将测试运行程序设置为 Microsoft.Testing.Platform",
"postActions/openInEditor/description": "在编辑器中打开 Test1.cs"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json
index 51fc6105a344..e677ca36d9a4 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup 固件方法",
"postActions/restoreNugetPackages/description": "還原此專案所需的 NuGet 套件。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "執行 'dotnet restore'",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "建立或更新 Microsoft.Testing.Platform 所需的 'global.json' 檔案。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "手動更新或建立 'global.json' 檔案,將測試執行器設定為 Microsoft.Testing.Platform",
"postActions/openInEditor/description": "在編輯器中開啟 Test1.cs"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/template.json
index 01977ec20d99..642d2f3b5a19 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/template.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/.template.config/template.json
@@ -240,7 +240,9 @@
"parentPropertyPath": "test",
"newJsonPropertyName": "runner",
"newJsonPropertyValue": "Microsoft.Testing.Platform",
- "detectRepositoryRootForFileCreation": true
+ "detectRepositoryRoot": true,
+ "includeAllDirectoriesInSearch": false,
+ "includeAllParentDirectoriesInSearch": true
},
"continueOnError": true
},
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/Company.TestProject1.csproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/Company.TestProject1.csproj
index a8c889eafa29..415f0f4b220a 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-CSharp/Company.TestProject1.csproj
+++ b/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/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.cs.json
index b7ff6b32d45f..044ee2de540a 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.cs.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.cs.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Metoda testovacího přípravku TestCleanup",
"postActions/restoreNugetPackages/description": "Obnoví balíčky NuGet vyžadované tímto projektem.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Spustit dotnet restore",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Vytvořte nebo aktualizujte soubor global.json vyžadovaný Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Ručně aktualizujte nebo vytvořte soubor global.json, který nastaví spouštěč testů na Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Otevře Test1.fs v editoru."
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.de.json
index 83a5669b3e1b..d63f705d430c 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.de.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.de.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Fixierungsmethode \"TestCleanup\"",
"postActions/restoreNugetPackages/description": "Stellt die NuGet-Pakete wieder her, die für dieses Projekt erforderlich sind.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "\"dotnet restore\" ausführen",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Erstellen oder aktualisieren Sie die für die Microsoft.Testing.Platform erforderliche Datei „global.json“.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Aktualisieren oder erstellen Sie die Datei „global.json“ manuell, um den Testausführer auf Microsoft.Testing.Platform einzustellen.",
"postActions/openInEditor/description": "Öffnet Test1.fs im Editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.es.json
index 1e9575a5346f..e8453105b8d7 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.es.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.es.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Método de accesorio TestCleanup",
"postActions/restoreNugetPackages/description": "Restaure los paquetes NuGet necesarios para este proyecto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Ejecutar \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Cree o actualice el archivo \"global.json\" requerido por Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Actualizar o crear manualmente el archivo \"global.json\" estableciendo el ejecutor de pruebas en Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Abrir Test1.fs en el editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.fr.json
index 8c0eb4a05506..5d164b74452d 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.fr.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.fr.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Méthode de fixture TestCleanup",
"postActions/restoreNugetPackages/description": "Restaurez les packages NuGet requis par ce projet.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Exécutez « dotnet restore »",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Créez ou mettez à jour le fichier « global.json » requis par Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Mettez à jour ou créez manuellement le fichier « global.json » en définissant l’exécuteur de tests sur Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Ouvre Test1.fs dans l’éditeur"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.it.json
index db8b42b1f617..58a28f206074 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.it.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.it.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Metodo fixture TestCleanup",
"postActions/restoreNugetPackages/description": "Ripristina i pacchetti NuGet richiesti da questo progetto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Esegui 'dotnet restore'",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Creare o aggiornare il file 'global.json' richiesto da Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Aggiornare o creare manualmente il file 'global.json' impostando il test runner su Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Apre Test1.fs nell'editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ja.json
index 93ecd87fadd3..843eb3d0de87 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ja.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ja.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup フィクスチャ メソッド",
"postActions/restoreNugetPackages/description": "このプロジェクトに必要な NuGet パッケージを復元します。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "'dotnet restore' を実行する",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform に必要な 'global.json' ファイルを作成または更新します。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "テスト ランナーを Microsoft.Testing.Platform に設定する 'global.json' ファイルを手動で更新または作成する",
"postActions/openInEditor/description": "エディターで Test1.fs を開きます"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ko.json
index 4d43f0445d48..6d0c6975eff3 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ko.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ko.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup fixture 메서드",
"postActions/restoreNugetPackages/description": "이 프로젝트에 필요한 NuGet 패키지를 복원합니다.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "'dotnet restore' 실행",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform에 필요한 'global.json' 파일을 만들거나 업데이트합니다.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "테스트 실행기를 Microsoft.Testing.Platform으로 설정하는 'global.json' 파일을 수동으로 만들거나 업데이트합니다.",
"postActions/openInEditor/description": "편집기에서 Test1.fs 열기"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pl.json
index 0562966c9b78..1d42137802a6 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pl.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pl.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup — metoda początkowa",
"postActions/restoreNugetPackages/description": "Przywróć pakiety NuGet wymagane przez ten projekt.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Uruchom polecenie „dotnet restore”",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Utwórz lub zaktualizuj plik „global.json” wymagany przez Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Ręcznie zaktualizuj lub utwórz plik „global.json” ustawiając moduł uruchamiający testy na Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Otwiera plik Test1.fs w edytorze"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pt-BR.json
index 1e0e1f8c92d2..f7d966d58048 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pt-BR.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pt-BR.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Método de acessório TestCleanup",
"postActions/restoreNugetPackages/description": "Restaura os pacotes do NuGet exigidos por este projeto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Executa \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Criar ou atualizar o arquivo 'global.json' necessário para o Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Atualize ou crie manualmente o arquivo 'global.json', definindo o test runner como Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Abre o Test1.fs no editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ru.json
index d82d72c10c99..c1037df6c803 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ru.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ru.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Метод работы со средствами TestCleanup",
"postActions/restoreNugetPackages/description": "Восстановление пакетов NuGet, необходимых для этого проекта.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Выполнить команду \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Создайте или обновите файл global.json, необходимый для Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Вручную обновите или создайте файл global.json, настраивающий Microsoft.Testing.Platform в качестве средства выполнения тестов",
"postActions/openInEditor/description": "Открывает Test1.fs в редакторе"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.tr.json
index 1cd7b63e0a39..f4f8ad417a2e 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.tr.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.tr.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup düzen yöntemi",
"postActions/restoreNugetPackages/description": "Bu projenin gerektirdiği NuGet paketlerini geri yükleyin.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "\"dotnet restore\" çalıştır",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform tarafından gerekli olan ‘global.json’ dosyasını oluşturun veya güncelleştirin.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Test çalıştırıcısını Microsoft.Testing.Platform olarak ayarlayarak ‘global.json’ dosyasını manuel olarak güncelleştirin veya oluşturun.",
"postActions/openInEditor/description": "Test1.fs'yi düzenleyicide açar"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hans.json
index bf7797f48535..64ab47000ce2 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hans.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hans.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup 固定例程方法",
"postActions/restoreNugetPackages/description": "还原此项目所需的 NuGet 包。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "运行 \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "创建或更新 Microsoft.Testing.Platform 所需的 \"global.json\" 文件。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "手动更新或创建 \"global.json\" 文件,将测试运行程序设置为 Microsoft.Testing.Platform",
"postActions/openInEditor/description": "在编辑器中打开 Test1.fs"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hant.json
index 0f55f462362c..838f19ee002d 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hant.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hant.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup 固件方法",
"postActions/restoreNugetPackages/description": "還原此專案所需的 NuGet 套件。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "執行 'dotnet restore'",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "建立或更新 Microsoft.Testing.Platform 所需的 'global.json' 檔案。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "手動更新或建立 'global.json' 檔案,將測試執行器設定為 Microsoft.Testing.Platform",
"postActions/openInEditor/description": "在編輯器中開啟 Test1.fs"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/template.json
index 022ffe70b9cf..ed388b0b28da 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/template.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/.template.config/template.json
@@ -240,7 +240,9 @@
"parentPropertyPath": "test",
"newJsonPropertyName": "runner",
"newJsonPropertyValue": "Microsoft.Testing.Platform",
- "detectRepositoryRootForFileCreation": true
+ "detectRepositoryRoot": true,
+ "includeAllDirectoriesInSearch": false,
+ "includeAllParentDirectoriesInSearch": true
},
"continueOnError": true
},
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/Company.TestProject1.fsproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/Company.TestProject1.fsproj
index 40e22d8c07c0..6c64e1cd1165 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-FSharp/Company.TestProject1.fsproj
+++ b/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/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.cs.json
index d51fe797a198..7fc05eea04bf 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.cs.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.cs.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Metoda testovacího přípravku TestCleanup",
"postActions/restoreNugetPackages/description": "Obnoví balíčky NuGet vyžadované tímto projektem.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Spustit dotnet restore",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Vytvořte nebo aktualizujte soubor global.json vyžadovaný Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Ručně aktualizujte nebo vytvořte soubor global.json, který nastaví spouštěč testů na Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Otevře Test1.vb v editoru."
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.de.json
index 91296abf8c4b..b75b7acc6f3a 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.de.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.de.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Fixierungsmethode \"TestCleanup\"",
"postActions/restoreNugetPackages/description": "Stellt die NuGet-Pakete wieder her, die für dieses Projekt erforderlich sind.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "\"dotnet restore\" ausführen",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Erstellen oder aktualisieren Sie die für die Microsoft.Testing.Platform erforderliche Datei „global.json“.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Aktualisieren oder erstellen Sie die Datei „global.json“ manuell, um den Testausführer auf Microsoft.Testing.Platform einzustellen.",
"postActions/openInEditor/description": "Öffnet Test1.vb im Editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.es.json
index 26c232daac1e..5975b418d535 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.es.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.es.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Método de accesorio TestCleanup",
"postActions/restoreNugetPackages/description": "Restaure los paquetes NuGet necesarios para este proyecto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Ejecutar \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Cree o actualice el archivo \"global.json\" requerido por Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Actualizar o crear manualmente el archivo \"global.json\" estableciendo el ejecutor de pruebas en Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Abrir Test1.vb en el editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.fr.json
index 38dd553aa8a8..dc3b33577aa9 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.fr.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.fr.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Méthode de fixture TestCleanup",
"postActions/restoreNugetPackages/description": "Restaurez les packages NuGet requis par ce projet.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Exécutez « dotnet restore »",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Créez ou mettez à jour le fichier « global.json » requis par Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Mettez à jour ou créez manuellement le fichier « global.json » en définissant l’exécuteur de tests sur Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Ouvre Test1.vb dans l’éditeur"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.it.json
index d90ba815124c..6d460d9c878f 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.it.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.it.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Metodo fixture TestCleanup",
"postActions/restoreNugetPackages/description": "Ripristina i pacchetti NuGet richiesti da questo progetto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Esegui 'dotnet restore'",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Creare o aggiornare il file 'global.json' richiesto da Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Aggiornare o creare manualmente il file 'global.json' impostando il test runner su Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Apre Test1.vb nell'editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ja.json
index 1e5086d83fa6..b633c77f31e8 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ja.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ja.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup フィクスチャ メソッド",
"postActions/restoreNugetPackages/description": "このプロジェクトに必要な NuGet パッケージを復元します。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "'dotnet restore' を実行する",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform に必要な 'global.json' ファイルを作成または更新します。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "テスト ランナーを Microsoft.Testing.Platform に設定する 'global.json' ファイルを手動で更新または作成する",
"postActions/openInEditor/description": "エディターで Test1.vb を開きます"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ko.json
index b9023d907f62..ecb7b8cfc7e3 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ko.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ko.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup fixture 메서드",
"postActions/restoreNugetPackages/description": "이 프로젝트에 필요한 NuGet 패키지를 복원합니다.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "'dotnet restore' 실행",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform에 필요한 'global.json' 파일을 만들거나 업데이트합니다.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "테스트 실행기를 Microsoft.Testing.Platform으로 설정하는 'global.json' 파일을 수동으로 만들거나 업데이트합니다.",
"postActions/openInEditor/description": "편집기에서 Test1.vb 열기"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pl.json
index 2df4f1064515..b27d9229cbde 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pl.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pl.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup — metoda początkowa",
"postActions/restoreNugetPackages/description": "Przywróć pakiety NuGet wymagane przez ten projekt.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Uruchom polecenie „dotnet restore”",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Utwórz lub zaktualizuj plik „global.json” wymagany przez Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Ręcznie zaktualizuj lub utwórz plik „global.json” ustawiając moduł uruchamiający testy na Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Otwiera plik Test1.vb w edytorze"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pt-BR.json
index b0311cbc2cac..a9207ecaa0fc 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pt-BR.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pt-BR.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Método de acessório TestCleanup",
"postActions/restoreNugetPackages/description": "Restaura os pacotes do NuGet exigidos por este projeto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Executa \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Criar ou atualizar o arquivo 'global.json' necessário para o Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Atualize ou crie manualmente o arquivo 'global.json', definindo o test runner como Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Abre o Test1.vb no editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ru.json
index b5a84d8cd027..a9c905169569 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ru.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ru.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Метод работы со средствами TestCleanup",
"postActions/restoreNugetPackages/description": "Восстановление пакетов NuGet, необходимых для этого проекта.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Выполнить команду \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Создайте или обновите файл global.json, необходимый для Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Вручную обновите или создайте файл global.json, настраивающий Microsoft.Testing.Platform в качестве средства выполнения тестов",
"postActions/openInEditor/description": "Открывает Test1.vb в редакторе"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.tr.json
index 88d9f7cd1761..7a131994c2bc 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.tr.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.tr.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup düzen yöntemi",
"postActions/restoreNugetPackages/description": "Bu projenin gerektirdiği NuGet paketlerini geri yükleyin.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "\"dotnet restore\" çalıştır",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform tarafından gerekli olan ‘global.json’ dosyasını oluşturun veya güncelleştirin.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Test çalıştırıcısını Microsoft.Testing.Platform olarak ayarlayarak ‘global.json’ dosyasını manuel olarak güncelleştirin veya oluşturun.",
"postActions/openInEditor/description": "Test1.vb'yi düzenleyicide açar"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json
index 53b04ad750ca..c0c1696f53c4 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup 固定例程方法",
"postActions/restoreNugetPackages/description": "还原此项目所需的 NuGet 包。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "运行 \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "创建或更新 Microsoft.Testing.Platform 所需的 \"global.json\" 文件。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "手动更新或创建 \"global.json\" 文件,将测试运行程序设置为 Microsoft.Testing.Platform",
"postActions/openInEditor/description": "在编辑器中打开 Test1.vb"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json
index 9a74906310ef..3aefbbe58e9f 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json
@@ -52,7 +52,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup 固件方法",
"postActions/restoreNugetPackages/description": "還原此專案所需的 NuGet 套件。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "執行 'dotnet restore'",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "建立或更新 Microsoft.Testing.Platform 所需的 'global.json' 檔案。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "手動更新或建立 'global.json' 檔案,將測試執行器設定為 Microsoft.Testing.Platform",
"postActions/openInEditor/description": "在編輯器中開啟 Test1.vb"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/template.json
index cca88e73c3cd..a110969e6973 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/template.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/.template.config/template.json
@@ -240,7 +240,9 @@
"parentPropertyPath": "test",
"newJsonPropertyName": "runner",
"newJsonPropertyValue": "Microsoft.Testing.Platform",
- "detectRepositoryRootForFileCreation": true
+ "detectRepositoryRoot": true,
+ "includeAllDirectoriesInSearch": false,
+ "includeAllParentDirectoriesInSearch": true
},
"continueOnError": true
},
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj
index a8c889eafa29..415f0f4b220a 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj
+++ b/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/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.cs.json
index 70f943fbeceb..648f92bd3831 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.cs.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.cs.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Metoda testovacího přípravku TestCleanup",
"postActions/restoreNugetPackages/description": "Obnoví balíčky NuGet vyžadované tímto projektem.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Spustit dotnet restore",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Vytvořte nebo aktualizujte soubor global.json vyžadovaný Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Ručně aktualizujte nebo vytvořte soubor global.json, který nastaví spouštěč testů na Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Otevře Test1.cs v editoru."
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.de.json
index a033b36b85f2..7f9ccea06133 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.de.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.de.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Fixierungsmethode \"TestCleanup\"",
"postActions/restoreNugetPackages/description": "Stellt die NuGet-Pakete wieder her, die für dieses Projekt erforderlich sind.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "\"dotnet restore\" ausführen",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Erstellen oder aktualisieren Sie die für die Microsoft.Testing.Platform erforderliche Datei „global.json“.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Aktualisieren oder erstellen Sie die Datei „global.json“ manuell, um den Testausführer auf Microsoft.Testing.Platform einzustellen.",
"postActions/openInEditor/description": "Öffnet Test1.cs im Editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.es.json
index dafa0d5fcefb..64561fd033d4 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.es.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.es.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Método de accesorio TestCleanup",
"postActions/restoreNugetPackages/description": "Restaure los paquetes NuGet necesarios para este proyecto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Ejecutar \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Cree o actualice el archivo \"global.json\" requerido por Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Actualizar o crear manualmente el archivo \"global.json\" estableciendo el ejecutor de pruebas en Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Abrir Test1.cs en el editor."
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.fr.json
index a42ccf5c7cde..ea1459b7e9ab 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.fr.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.fr.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Méthode de fixture TestCleanup",
"postActions/restoreNugetPackages/description": "Restaurez les packages NuGet requis par ce projet.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Exécutez « dotnet restore »",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Créez ou mettez à jour le fichier « global.json » requis par Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Mettez à jour ou créez manuellement le fichier « global.json » en définissant l’exécuteur de tests sur Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Ouvre Test1.cs dans l’éditeur"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.it.json
index 3cfad9d1ecc3..5acc742cb7af 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.it.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.it.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Metodo fixture TestCleanup",
"postActions/restoreNugetPackages/description": "Ripristina i pacchetti NuGet richiesti da questo progetto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Esegui 'dotnet restore'",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Creare o aggiornare il file 'global.json' richiesto da Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Aggiornare o creare manualmente il file 'global.json' impostando il test runner su Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Apre Test1.cs nell'editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ja.json
index 0cffb118b6ed..00caa4fbecee 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ja.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ja.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup フィクスチャ メソッド",
"postActions/restoreNugetPackages/description": "このプロジェクトに必要な NuGet パッケージを復元します。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "'dotnet restore' を実行する",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform に必要な 'global.json' ファイルを作成または更新します。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "テスト ランナーを Microsoft.Testing.Platform に設定する 'global.json' ファイルを手動で更新または作成する",
"postActions/openInEditor/description": "エディターで Test1.cs を開きます"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ko.json
index 04e74ff275e0..91eb4cc23954 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ko.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ko.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup fixture 메서드",
"postActions/restoreNugetPackages/description": "이 프로젝트에 필요한 NuGet 패키지를 복원합니다.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "'dotnet restore' 실행",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform에 필요한 'global.json' 파일을 만들거나 업데이트합니다.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "테스트 실행기를 Microsoft.Testing.Platform으로 설정하는 'global.json' 파일을 수동으로 만들거나 업데이트합니다.",
"postActions/openInEditor/description": "편집기에서 Test1.cs 열기"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.pl.json
index 7822568a090c..be9450819ab2 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.pl.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.pl.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup — metoda początkowa",
"postActions/restoreNugetPackages/description": "Przywróć pakiety NuGet wymagane przez ten projekt.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Uruchom polecenie „dotnet restore”",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Utwórz lub zaktualizuj plik „global.json” wymagany przez Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Ręcznie zaktualizuj lub utwórz plik „global.json” ustawiając moduł uruchamiający testy na Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Otwiera plik Test1.cs w edytorze"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json
index b16e73aaff84..10f54ae4f26c 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Método de acessório TestCleanup",
"postActions/restoreNugetPackages/description": "Restaura os pacotes do NuGet exigidos por este projeto.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Executa \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Criar ou atualizar o arquivo 'global.json' necessário para o Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Atualize ou crie manualmente o arquivo 'global.json', definindo o test runner como Microsoft.Testing.Platform",
"postActions/openInEditor/description": "Abre o Test1.cs no editor"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ru.json
index 62dd753e1e66..1651693ff9ee 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ru.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.ru.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "Метод работы со средствами TestCleanup",
"postActions/restoreNugetPackages/description": "Восстановление пакетов NuGet, необходимых для этого проекта.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "Выполнить команду \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Создайте или обновите файл global.json, необходимый для Microsoft.Testing.Platform.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Вручную обновите или создайте файл global.json, настраивающий Microsoft.Testing.Platform в качестве средства выполнения тестов",
"postActions/openInEditor/description": "Открывает Test1.cs редакторе"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.tr.json
index a0fe5d119211..500badeba886 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.tr.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.tr.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup düzen yöntemi",
"postActions/restoreNugetPackages/description": "Bu projenin gerektirdiği NuGet paketlerini geri yükleyin.",
"postActions/restoreNugetPackages/manualInstructions/default/text": "\"dotnet restore\" çalıştır",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "Microsoft.Testing.Platform tarafından gerekli olan ‘global.json’ dosyasını oluşturun veya güncelleştirin.",
+ "postActions/addJsonProperty/manualInstructions/default/text": "Test çalıştırıcısını Microsoft.Testing.Platform olarak ayarlayarak ‘global.json’ dosyasını manuel olarak güncelleştirin veya oluşturun.",
"postActions/openInEditor/description": "Test1.cs'yi düzenleyicide açar"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json
index d3813429eb2c..ef8e55b747cc 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup 固定例程方法",
"postActions/restoreNugetPackages/description": "还原此项目所需的 NuGet 包。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "运行 \"dotnet restore\"",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "创建或更新 Microsoft.Testing.Platform 所需的 \"global.json\" 文件。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "手动更新或创建 \"global.json\" 文件,将测试运行程序设置为 Microsoft.Testing.Platform",
"postActions/openInEditor/description": "在编辑器中打开 Test1.cs"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json
index 65f448819360..0b99b95bc994 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json
@@ -57,7 +57,7 @@
"symbols/Fixture/choices/TestCleanup/description": "TestCleanup 固件方法",
"postActions/restoreNugetPackages/description": "還原此專案所需的 NuGet 套件。",
"postActions/restoreNugetPackages/manualInstructions/default/text": "執行 'dotnet restore'",
- "postActions/addJsonProperty/description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.",
- "postActions/addJsonProperty/manualInstructions/default/text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform",
+ "postActions/addJsonProperty/description": "建立或更新 Microsoft.Testing.Platform 所需的 'global.json' 檔案。",
+ "postActions/addJsonProperty/manualInstructions/default/text": "手動更新或建立 'global.json' 檔案,將測試執行器設定為 Microsoft.Testing.Platform",
"postActions/openInEditor/description": "在編輯器中開啟 Test1.cs"
}
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/template.json
index b55dff5e27a9..cca0c7262957 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/template.json
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/.template.config/template.json
@@ -260,7 +260,9 @@
"parentPropertyPath": "test",
"newJsonPropertyName": "runner",
"newJsonPropertyValue": "Microsoft.Testing.Platform",
- "detectRepositoryRootForFileCreation": true
+ "detectRepositoryRoot": true,
+ "includeAllDirectoriesInSearch": false,
+ "includeAllParentDirectoriesInSearch": true
},
"continueOnError": true
},
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj
index c2484950c146..2cffa453be01 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj
+++ b/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/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-CSharp/Company.TestProject1.csproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-CSharp/Company.TestProject1.csproj
index 3eef41cd1588..bbcb92a579c5 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-CSharp/Company.TestProject1.csproj
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-CSharp/Company.TestProject1.csproj
@@ -6,34 +6,19 @@
Company.TestProject1enableenable
- Exetruefalse
-
-
-
-
-
-
-
-
-
-
- false
+
-
-
-
-
-
-
+
+
-
+
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-CSharp/xunit.runner.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-CSharp/xunit.runner.json
deleted file mode 100644
index 86c7ea05b16c..000000000000
--- a/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/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/Company.TestProject1.fsproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/Company.TestProject1.fsproj
index 3f4c2abd455e..bf9c5b0b607e 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/Company.TestProject1.fsproj
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/Company.TestProject1.fsproj
@@ -4,20 +4,8 @@
net10.0TargetFrameworkOverrideCompany.TestProject1
- Exetruefalse
-
-
-
-
-
-
-
-
-
-
- false
@@ -25,13 +13,10 @@
+
-
-
-
-
-
-
+
+
-
+
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/xunit.runner.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-FSharp/xunit.runner.json
deleted file mode 100644
index 86c7ea05b16c..000000000000
--- a/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/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj
index 10d29b506258..d88c072952f9 100644
--- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj
+++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj
@@ -4,30 +4,15 @@
Company.TestProject1net10.0TargetFrameworkOverride
- Exetruefalse
-
-
-
-
-
-
-
-
-
-
- false
+
-
-
-
-
-
-
+
+
-
+
\ No newline at end of file
diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/xunit.runner.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.10.0/content/XUnit-VisualBasic/xunit.runner.json
deleted file mode 100644
index 86c7ea05b16c..000000000000
--- a/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/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetCoreAppForTelemetry.cs b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetCoreAppForTelemetry.cs
index 54bc27a974d3..2dfa4c6fda50 100644
--- a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetCoreAppForTelemetry.cs
+++ b/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/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsRuntimeComponent.cs b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsRuntimeComponent.cs
index f96d48aa0a12..367227f02a97 100644
--- a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsRuntimeComponent.cs
+++ b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsRuntimeComponent.cs
@@ -197,7 +197,7 @@ static void Main(string[] args)
.HaveStdOut("(0, 0)");
}
- [FullMSBuildOnlyFact]
+ [FullMSBuildOnlyFact(Skip = "https://github.com/dotnet/sdk/issues/51361")]
public void WinMDInteropProjectCanBeReferenced()
{
diff --git a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToReferenceAProject.cs b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToReferenceAProject.cs
index a115fc358fbb..8d8382547de9 100644
--- a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToReferenceAProject.cs
+++ b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToReferenceAProject.cs
@@ -55,9 +55,9 @@ public void It_checks_for_valid_platform_references(string referencerTarget, str
[InlineData($"{ToolsetInfo.CurrentTargetFramework};net45", true, "netstandard1.4", true, false, false)]
[InlineData($"{ToolsetInfo.CurrentTargetFramework};net46", true, "net45;netstandard1.6", true, true, true)]
[InlineData($"{ToolsetInfo.CurrentTargetFramework};net45", true, "net46;netstandard1.6", true, false, false)]
- [InlineData("v4.5.2", false, "netstandard1.6", true, true, false)]
+ [InlineData("v4.6.2", false, "netstandard1.6", true, true, true)]
[InlineData("v4.7.2", false, "netstandard1.6;net472", true, true, true)]
- [InlineData("v4.5.2", false, "netstandard1.6;net472", true, true, false)]
+ [InlineData("v4.6.2", false, "netstandard1.6;net472", true, true, true)]
public void It_checks_for_valid_references(string referencerTarget, bool referencerIsSdkProject,
string dependencyTarget, bool dependencyIsSdkProject,
bool restoreSucceeds, bool buildSucceeds)
diff --git a/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs b/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs
index ba14cd54eebc..2f473b12d72f 100644
--- a/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs
+++ b/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/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs
index 20afab0e873f..2f28bcd53135 100644
--- a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs
+++ b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs
@@ -253,7 +253,7 @@ public void NativeAot_app_builds_with_config_when_PublishAot_is_enabled(string t
private const string Net7ExplicitPackageVersion = "7.0.0";
- [RequiresMSBuildVersionTheory("17.0.0.32901")]
+ [RequiresMSBuildVersionTheory("17.0.0.32901", Skip = "https://github.com/dotnet/sdk/issues/51361")]
[InlineData("net7.0")]
public void NativeAot_hw_runs_with_PackageReference_PublishAot_is_enabled(string targetFramework)
{
@@ -606,7 +606,7 @@ public void IsAotCompatible_implies_enable_analyzers(string targetFramework)
.And.NotHaveStdOutContaining("warning IL3002");
}
- [RequiresMSBuildVersionTheory("17.0.0.32901")]
+ [RequiresMSBuildVersionTheory("17.0.0.32901", Skip = "https://github.com/dotnet/sdk/issues/51361")]
[InlineData("net5.0", true)]
[InlineData("net6.0", true)]
[InlineData("net7.0", false)]
@@ -706,7 +706,7 @@ public void Requires_analyzers_produce_warnings_without_PublishAot_being_set(str
.And.HaveStdOutContaining("warning IL3002");
}
- [RequiresMSBuildVersionTheory("17.0.0.32901")]
+ [RequiresMSBuildVersionTheory("17.0.0.32901", Skip = "https://github.com/dotnet/sdk/issues/51361")]
[MemberData(nameof(Net7Plus), MemberType = typeof(PublishTestUtils))]
public void NativeAot_compiler_runs_when_PublishAot_is_enabled(string targetFramework)
{
diff --git a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishIncrementally.cs b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishIncrementally.cs
index c47c60089692..9cd038e21ff5 100644
--- a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishIncrementally.cs
+++ b/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/test/Microsoft.NET.Restore.Tests/GivenThatWeWantAutomaticTargetingPackReferences.cs b/test/Microsoft.NET.Restore.Tests/GivenThatWeWantAutomaticTargetingPackReferences.cs
index b5cdde0bf1c5..e9f334f7c82c 100644
--- a/test/Microsoft.NET.Restore.Tests/GivenThatWeWantAutomaticTargetingPackReferences.cs
+++ b/test/Microsoft.NET.Restore.Tests/GivenThatWeWantAutomaticTargetingPackReferences.cs
@@ -19,7 +19,7 @@ public GivenThatWeWantAutomaticTargetingPackReferences(ITestOutputHelper log) :
[Theory]
[InlineData("4.7.1")]
[InlineData("4.7.2")]
- [InlineData("4.5.2")]
+ [InlineData("4.6.2")]
[InlineData("4.8")]
public void It_restores_net_framework_project_successfully(string version)
{
diff --git a/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/ScopedCssIntegrationTests.cs b/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/ScopedCssIntegrationTests.cs
index 9668d8656913..6155a3498987 100644
--- a/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/ScopedCssIntegrationTests.cs
+++ b/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/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/Globbing/StaticWebAssetGlobMatcherTest.cs b/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/Globbing/StaticWebAssetGlobMatcherTest.cs
index f8061c5d6ba1..fb2746fb1ce5 100644
--- a/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/Globbing/StaticWebAssetGlobMatcherTest.cs
+++ b/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/Globbing/StaticWebAssetGlobMatcherTest.cs
@@ -27,6 +27,29 @@ namespace Microsoft.AspNetCore.StaticWebAssets.Tasks.Test;
// Recursive wildcard in the middle 'a/**/c'
public partial class StaticWebAssetGlobMatcherTest
{
+ [Theory]
+ [InlineData("**/*.razor.js", "Components/Pages/RegularComponent.razor.js", "Components/Pages/RegularComponent.razor.js")]
+ [InlineData("**/*.razor.js", "Components/User.Profile.Details.razor.js", "Components/User.Profile.Details.razor.js")]
+ [InlineData("**/*.razor.js", "Components/Area/Sub/Feature/User.Profile.Details.razor.js", "Components/Area/Sub/Feature/User.Profile.Details.razor.js")]
+ [InlineData("**/*.razor.js", "Components/Area/Sub/Feature/Deep.Component.Name.With.Many.Parts.razor.js", "Components/Area/Sub/Feature/Deep.Component.Name.With.Many.Parts.razor.js")]
+ [InlineData("**/*.cshtml.js", "Pages/Shared/_Host.cshtml.js", "Pages/Shared/_Host.cshtml.js")]
+ [InlineData("**/*.cshtml.js", "Areas/Admin/Pages/Dashboard.cshtml.js", "Areas/Admin/Pages/Dashboard.cshtml.js")]
+ [InlineData("*.lib.module.js", "Widget.lib.module.js", "Widget.lib.module.js")]
+ [InlineData("*.razor.css", "Component.razor.css", "Component.razor.css")]
+ [InlineData("*.cshtml.css", "View.cshtml.css", "View.cshtml.css")]
+ [InlineData("*.modules.json", "app.modules.json", "app.modules.json")]
+ [InlineData("*.lib.module.js", "Rcl.Client.Feature.lib.module.js", "Rcl.Client.Feature.lib.module.js")]
+ public void Can_Match_WellKnownExistingPatterns(string pattern, string path, string expectedStem)
+ {
+ var matcher = new StaticWebAssetGlobMatcherBuilder();
+ matcher.AddIncludePatterns(pattern);
+ var globMatcher = matcher.Build();
+
+ var match = globMatcher.Match(path);
+ Assert.True(match.IsMatch);
+ Assert.Equal(pattern, match.Pattern);
+ Assert.Equal(expectedStem, match.Stem);
+ }
[Fact]
public void CanMatchLiterals()
{
diff --git a/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/SdkAnalyzerAssemblyRedirectorTests.cs b/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/SdkAnalyzerAssemblyRedirectorTests.cs
index 62a042d8f419..956161b134a8 100644
--- a/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/SdkAnalyzerAssemblyRedirectorTests.cs
+++ b/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/test/TestAssets/TestProjects/WatchAspire/WatchAspire.ApiService/Program.cs b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.ApiService/Program.cs
index 29ac848cd132..95a823165073 100644
--- a/test/TestAssets/TestProjects/WatchAspire/WatchAspire.ApiService/Program.cs
+++ b/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/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/Program.cs b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/Program.cs
index 4e0bf9d4cee6..7ef5c7a828ee 100644
--- a/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/Program.cs
+++ b/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/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/WatchAspire.AppHost.csproj b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/WatchAspire.AppHost.csproj
index 90483a02df60..3f394f6f83c0 100644
--- a/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/WatchAspire.AppHost.csproj
+++ b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.AppHost/WatchAspire.AppHost.csproj
@@ -9,9 +9,10 @@
-
-
-
+
+
+
+
diff --git a/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Program.cs b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Program.cs
new file mode 100644
index 000000000000..0abee487007d
--- /dev/null
+++ b/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/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Properties/launchSettings.json b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Properties/launchSettings.json
new file mode 100644
index 000000000000..a312e8fb30bf
--- /dev/null
+++ b/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/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/WatchAspire.MigrationService.csproj b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/WatchAspire.MigrationService.csproj
new file mode 100644
index 000000000000..621a330ee1b4
--- /dev/null
+++ b/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/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Worker.cs b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/Worker.cs
new file mode 100644
index 000000000000..4792261219db
--- /dev/null
+++ b/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/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.Development.json b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.Development.json
new file mode 100644
index 000000000000..cd7d0bc9100b
--- /dev/null
+++ b/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/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.json b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.json
new file mode 100644
index 000000000000..0c208ae9181e
--- /dev/null
+++ b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.MigrationService/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/test/TestAssets/TestProjects/WatchAspire/WatchAspire.Wasm/App.razor b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.Wasm/App.razor
index 13f3043f0c49..eba23da9b5ae 100644
--- a/test/TestAssets/TestProjects/WatchAspire/WatchAspire.Wasm/App.razor
+++ b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.Wasm/App.razor
@@ -1,4 +1,4 @@
-
+
diff --git a/test/TestAssets/TestProjects/WatchAspire/WatchAspire.slnx b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.slnx
new file mode 100644
index 000000000000..d9a238e555dc
--- /dev/null
+++ b/test/TestAssets/TestProjects/WatchAspire/WatchAspire.slnx
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/test/TestAssets/TestProjects/WatchHotReloadApp/Program.cs b/test/TestAssets/TestProjects/WatchHotReloadApp/Program.cs
index f1d2a3b77bbd..7171e0a19260 100644
--- a/test/TestAssets/TestProjects/WatchHotReloadApp/Program.cs
+++ b/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/test/TestAssets/TestProjects/WatchRazorWithDeps/RazorApp/Components/Pages/Home.razor b/test/TestAssets/TestProjects/WatchRazorWithDeps/RazorApp/Components/Pages/Home.razor
index bb44fc2639e7..2daa1cadc252 100644
--- a/test/TestAssets/TestProjects/WatchRazorWithDeps/RazorApp/Components/Pages/Home.razor
+++ b/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/test/dotnet-watch-test-browser/Program.cs b/test/dotnet-watch-test-browser/Program.cs
new file mode 100644
index 000000000000..78f96cb73ccb
--- /dev/null
+++ b/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/test/dotnet-watch-test-browser/dotnet-watch-test-browser.csproj b/test/dotnet-watch-test-browser/dotnet-watch-test-browser.csproj
new file mode 100644
index 000000000000..408cb9159c99
--- /dev/null
+++ b/test/dotnet-watch-test-browser/dotnet-watch-test-browser.csproj
@@ -0,0 +1,14 @@
+
+
+ Exe
+ $(ToolsetTargetFramework)
+ MicrosoftAspNetCore
+ Microsoft.DotNet.Watch.UnitTests
+
+
+
+
+
+
+
+
diff --git a/test/dotnet-watch.Tests/Browser/BrowserLaunchTests.cs b/test/dotnet-watch.Tests/Browser/BrowserLaunchTests.cs
deleted file mode 100644
index f5fbf358d819..000000000000
--- a/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/test/dotnet-watch.Tests/Browser/BrowserRefreshServerTests.cs b/test/dotnet-watch.Tests/Browser/BrowserRefreshServerTests.cs
new file mode 100644
index 000000000000..236c99ec077d
--- /dev/null
+++ b/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/test/dotnet-watch.Tests/Browser/BrowserTests.cs b/test/dotnet-watch.Tests/Browser/BrowserTests.cs
new file mode 100644
index 000000000000..8fa4c00de4ef
--- /dev/null
+++ b/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/test/dotnet-watch.Tests/Build/EvaluationTests.cs b/test/dotnet-watch.Tests/Build/EvaluationTests.cs
index 5a6786875334..4c1bcbdbb30a 100644
--- a/test/dotnet-watch.Tests/Build/EvaluationTests.cs
+++ b/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/test/dotnet-watch.Tests/CommandLine/LaunchSettingsTests.cs b/test/dotnet-watch.Tests/CommandLine/LaunchSettingsTests.cs
index 24ee2076885b..95bbd1d79657 100644
--- a/test/dotnet-watch.Tests/CommandLine/LaunchSettingsTests.cs
+++ b/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/test/dotnet-watch.Tests/ConsoleReporterTests.cs b/test/dotnet-watch.Tests/ConsoleReporterTests.cs
index 7fb1c564451d..8df1601dc0dc 100644
--- a/test/dotnet-watch.Tests/ConsoleReporterTests.cs
+++ b/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/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs b/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs
index a7a1bcda1923..501ce980b20f 100644
--- a/test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs
+++ b/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();
@@ -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()
{
@@ -459,7 +517,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 +534,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 +572,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 +779,8 @@ class AppUpdateHandler
[PlatformSpecificFact(TestPlatforms.Windows)]
public async Task GracefulTermination_Windows()
{
+ var tfm = ToolsetInfo.CurrentTargetFramework;
+
var testAsset = TestAssets.CopyTestAsset("WatchHotReloadApp")
.WithSource();
@@ -739,7 +799,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 +809,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 +868,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 +900,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 +922,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 +938,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 +969,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 +982,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 +1205,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 +1226,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 +1272,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 +1283,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 +1296,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 +1322,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 +1355,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/test/dotnet-watch.Tests/HotReload/CompilationHandlerTests.cs b/test/dotnet-watch.Tests/HotReload/CompilationHandlerTests.cs
index bedd9d2a7c5c..9ac5030c4eba 100644
--- a/test/dotnet-watch.Tests/HotReload/CompilationHandlerTests.cs
+++ b/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/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs b/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs
index 76993fbe54e3..ff2c8491194f 100644
--- a/test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs
+++ b/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();
// rude edit in A (changing assembly level attribute):
UpdateSourceFile(serviceSourceA2, """
diff --git a/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs b/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs
index 6f2b2fc7e30a..c80299e56b73 100644
--- a/test/dotnet-watch.Tests/TestUtilities/AssertEx.cs
+++ b/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,24 @@ 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 not found in the output:"
+ : "Text not expected to be found in the output:");
+
message.AppendLine(expected);
message.AppendLine();
message.AppendLine("Actual output:");
@@ -256,15 +266,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/test/dotnet-watch.Tests/TestUtilities/TestBrowserRefreshServer.cs b/test/dotnet-watch.Tests/TestUtilities/TestBrowserRefreshServer.cs
new file mode 100644
index 000000000000..06acc9719b39
--- /dev/null
+++ b/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/test/dotnet-watch.Tests/TestUtilities/TestLogger.cs b/test/dotnet-watch.Tests/TestUtilities/TestLogger.cs
index 3a9add553aa0..5ae8e7dcd811 100644
--- a/test/dotnet-watch.Tests/TestUtilities/TestLogger.cs
+++ b/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/test/dotnet-watch.Tests/TestUtilities/TestLoggerFactory.cs b/test/dotnet-watch.Tests/TestUtilities/TestLoggerFactory.cs
new file mode 100644
index 000000000000..be1e69682952
--- /dev/null
+++ b/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/test/dotnet-watch.Tests/TestUtilities/WatchableApp.cs b/test/dotnet-watch.Tests/TestUtilities/WatchableApp.cs
index 8888b5634398..81bfd17aae20 100644
--- a/test/dotnet-watch.Tests/TestUtilities/WatchableApp.cs
+++ b/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/test/dotnet-watch.Tests/Watch/BuildEvaluatorTests.cs b/test/dotnet-watch.Tests/Watch/BuildEvaluatorTests.cs
index 1efccba2eb22..d673b618826c 100644
--- a/test/dotnet-watch.Tests/Watch/BuildEvaluatorTests.cs
+++ b/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/test/dotnet-watch.Tests/Watch/NoRestoreTests.cs b/test/dotnet-watch.Tests/Watch/NoRestoreTests.cs
index a28d91c3423e..895a9d6b779e 100644
--- a/test/dotnet-watch.Tests/Watch/NoRestoreTests.cs
+++ b/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/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj b/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj
index 6a81d97e1ed3..772d35b80517 100644
--- a/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj
+++ b/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj
@@ -16,10 +16,23 @@
-->
+
+
+
+
+
+ <_Files>@(TestBrowserOutput->'%(RootDir)%(Directory)*.*')
+
+
+ <_FileItem Include="$(_Files)" />
+
+
+
+
diff --git a/test/dotnet.Tests/CommandTests/MSBuild/FakeTelemetry.cs b/test/dotnet.Tests/CommandTests/MSBuild/FakeTelemetry.cs
index f5624bf0a482..bcb6a6dbfde1 100644
--- a/test/dotnet.Tests/CommandTests/MSBuild/FakeTelemetry.cs
+++ b/test/dotnet.Tests/CommandTests/MSBuild/FakeTelemetry.cs
@@ -9,12 +9,14 @@ 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)
{
- LogEntry = new LogEntry { EventName = eventName, Properties = properties, Measurement = measurements };
-
+ var entry = new LogEntry { EventName = eventName, Properties = properties, Measurement = measurements };
+ _logEntries.Add(entry);
}
public void Flush()
@@ -25,8 +27,8 @@ public void Dispose()
{
}
- public LogEntry LogEntry { get; private set; }
+ public LogEntry LogEntry => _logEntries.Count > 0 ? _logEntries[_logEntries.Count - 1] : null;
+ public IReadOnlyList LogEntries => _logEntries.AsReadOnly();
}
-
}
diff --git a/test/dotnet.Tests/CommandTests/MSBuild/GivenDotnetBuildInvocation.cs b/test/dotnet.Tests/CommandTests/MSBuild/GivenDotnetBuildInvocation.cs
index 08c5ee7071cd..8b6c7de5b074 100644
--- a/test/dotnet.Tests/CommandTests/MSBuild/GivenDotnetBuildInvocation.cs
+++ b/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/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs b/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs
index 75fd2ef787dd..12a75b9493ee 100644
--- a/test/dotnet.Tests/CommandTests/MSBuild/GivenMSBuildLogger.cs
+++ b/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
{
- { "TargetFrameworkVersion", "9a871d7066260764d4cb5047e4b10570271d04bd1da275681a4b12bce0b27496"},
- { "RuntimeIdentifier", "fb329000228cc5a24c264c57139de8bf854fc86fc18bf1c04ab61a2b5cb4b921"},
- { "SelfContained", "fb329000228cc5a24c264c57139de8bf854fc86fc18bf1c04ab61a2b5cb4b921"},
- { "UseApphost", "fb329000228cc5a24c264c57139de8bf854fc86fc18bf1c04ab61a2b5cb4b921"},
- { "OutputType", "d77982267d9699c2a57bcab5bb975a1935f6427002f52fd4569762fd72db3a94"},
- });
+ { "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/test/dotnet.Tests/CommandTests/Package/Add/GivenDotnetPackageAdd.cs b/test/dotnet.Tests/CommandTests/Package/Add/GivenDotnetPackageAdd.cs
index c924c1ac65bd..4bfa88903553 100644
--- a/test/dotnet.Tests/CommandTests/Package/Add/GivenDotnetPackageAdd.cs
+++ b/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/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs b/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs
index 27bf71fa48dc..72a600549d62 100644
--- a/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs
+++ b/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs
@@ -1,6 +1,9 @@
// 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;
using Microsoft.DotNet.Cli.Commands;
using Microsoft.DotNet.Cli.Commands.Run;
@@ -56,14 +59,139 @@ public void SameAsTemplate()
var dotnetProjectConvertProjectText = File.ReadAllText(dotnetProjectConvertProject);
var dotnetNewConsoleProjectText = File.ReadAllText(dotnetNewConsoleProject);
- // There are some differences: we add PublishAot=true.
+ // 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);
patchedDotnetProjectConvertProjectText.Should().Be(dotnetNewConsoleProjectText)
.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()
{
@@ -648,7 +776,7 @@ public void ProcessingSucceeds()
.Should().Be("Console.WriteLine();");
File.ReadAllText(Path.Join(testInstance.Path, "Program", "Program.csproj"))
- .Should().Be($"""
+ .Should().Match($"""
@@ -657,6 +785,8 @@ public void ProcessingSucceeds()
enableenabletrue
+ true
+ Program-*
@@ -668,6 +798,135 @@ public void ProcessingSucceeds()
""");
}
+ [Theory, CombinatorialData]
+ public void UserSecretsId_Overridden_ViaDirective(bool hasDirectiveBuildProps)
+ {
+ var testInstance = _testAssetsManager.CreateTestDirectory();
+ File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """
+ #:property UserSecretsId=MyIdFromDirective
+ Console.WriteLine();
+ """);
+
+ if (hasDirectiveBuildProps)
+ {
+ File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """
+
+
+ MyIdFromDirBuildProps
+
+
+ """);
+ }
+
+ new DotnetCommand(Log, "project", "convert", "Program.cs")
+ .WithWorkingDirectory(testInstance.Path)
+ .Execute()
+ .Should().Pass();
+
+ File.ReadAllText(Path.Join(testInstance.Path, "Program", "Program.csproj"))
+ .Should().Be($"""
+
+
+
+ Exe
+ {ToolsetInfo.CurrentTargetFramework}
+ enable
+ enable
+ true
+ true
+ MyIdFromDirective
+
+
+
+
+ """);
+ }
+
+ [Fact]
+ public void UserSecretsId_Overridden_ViaDirectoryBuildProps()
+ {
+ var testInstance = _testAssetsManager.CreateTestDirectory();
+
+ File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """
+ Console.WriteLine();
+ """);
+ File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """
+
+
+ MyIdFromDirBuildProps
+
+
+ """);
+
+ new DotnetCommand(Log, "project", "convert", "Program.cs")
+ .WithWorkingDirectory(testInstance.Path)
+ .Execute()
+ .Should().Pass();
+
+ File.ReadAllText(Path.Join(testInstance.Path, "Program", "Program.csproj"))
+ .Should().Be($"""
+
+
+
+ Exe
+ {ToolsetInfo.CurrentTargetFramework}
+ enable
+ enable
+ true
+ true
+
+
+
+
+ """);
+ }
+
+ [Theory, CombinatorialData]
+ public void UserSecretsId_Overridden_SameAsImplicit(bool hasDirective, bool hasDirectiveBuildProps)
+ {
+ const string implicitValue = "$(MSBuildProjectName)-$([MSBuild]::StableStringHash($(MSBuildProjectFullPath.ToLowerInvariant()), 'Sha256'))";
+
+ var testInstance = _testAssetsManager.CreateTestDirectory();
+ File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), $"""
+ {(hasDirective ? $"#:property UserSecretsId={implicitValue}" : "")}
+ Console.WriteLine();
+ """);
+
+ if (hasDirectiveBuildProps)
+ {
+ File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), $"""
+
+
+ {SecurityElement.Escape(implicitValue)}
+
+
+ """);
+ }
+
+ new DotnetCommand(Log, "project", "convert", "Program.cs")
+ .WithWorkingDirectory(testInstance.Path)
+ .Execute()
+ .Should().Pass();
+
+ File.ReadAllText(Path.Join(testInstance.Path, "Program", "Program.csproj"))
+ .Should().Match($"""
+
+
+
+ Exe
+ {ToolsetInfo.CurrentTargetFramework}
+ enable
+ enable
+ true
+ true
+ {(hasDirective ? SecurityElement.Escape(implicitValue) : "Program-*")}
+
+
+
+
+ """);
+ }
+
[Fact]
public void Directives()
{
@@ -691,6 +950,7 @@ public void Directives()
enableenabletrue
+ truenet472preview
@@ -721,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();
@@ -733,6 +994,7 @@ public void Directives_AllDefaultOverridden()
net472disablefalse
+ false1disable
@@ -762,6 +1024,7 @@ public void Directives_Variable()
enableenabletrue
+ trueMyValue
@@ -799,6 +1062,7 @@ public void Directives_DirectoryPath()
enableenabletrue
+ true
@@ -837,6 +1101,7 @@ public void Directives_Separators()
enableenabletrue
+ trueOne=a/bTwo/a=b
@@ -889,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()
{
@@ -904,10 +1213,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.
"""));
}
@@ -934,11 +1243,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
@@ -946,17 +1258,31 @@ public void Directives_Escaping()
enableenabletrue
+ 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]
@@ -980,6 +1306,7 @@ public void Directives_Whitespace()
enableenabletrue
+ trueValue"My package with spaces"
@@ -991,7 +1318,11 @@ public void Directives_Whitespace()
# ! /test
#! /program x
# :property Name=Value
- """);
+ """,
+ expectedErrors:
+ [
+ (3, CliCommandStrings.QuoteInDirective),
+ ]);
}
[Fact]
@@ -1006,6 +1337,7 @@ public void Directives_BlankLines()
enableenabletrue
+ true
@@ -1071,6 +1403,7 @@ public void Directives_AfterToken()
enableenabletrue
+ true12
@@ -1117,6 +1450,7 @@ public void Directives_AfterIf()
enableenabletrue
+ true12
@@ -1160,6 +1494,7 @@ public void Directives_Comments()
enableenabletrue
+ true12
@@ -1267,6 +1602,7 @@ public void Directives_VersionedSdkFirst()
enableenabletrue
+ true
@@ -1277,10 +1613,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();
@@ -1290,25 +1631,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/test/dotnet.Tests/CommandTests/Run/FileBasedAppSourceEditorTests.cs b/test/dotnet.Tests/CommandTests/Run/FileBasedAppSourceEditorTests.cs
index ea2480b032f4..371b29d7f314 100644
--- a/test/dotnet.Tests/CommandTests/Run/FileBasedAppSourceEditorTests.cs
+++ b/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/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
index 2c87e8cc7469..3f0b93c776ea 100644
--- a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
+++ b/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()
{
@@ -1483,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()
{
@@ -1695,7 +2049,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 +2095,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}");
""");
@@ -2191,6 +2543,70 @@ public void ProjectReference_Errors()
string.Format(CliStrings.MoreThanOneProjectInDirectory, Path.Join(testInstance.Path, "dir/"))));
}
+ [Theory] // https://github.com/dotnet/aspnetcore/issues/63440
+ [InlineData(true, null)]
+ [InlineData(false, null, Skip = "Needs https://github.com/dotnet/aspnetcore/pull/63496")]
+ [InlineData(true, "test-id")]
+ [InlineData(false, "test-id", Skip = "Needs https://github.com/dotnet/aspnetcore/pull/63496")]
+ public void UserSecrets(bool useIdArg, string? userSecretsId)
+ {
+ var testInstance = _testAssetsManager.CreateTestDirectory();
+
+ string code = $"""
+ #:package Microsoft.Extensions.Configuration.UserSecrets@{CSharpCompilerCommand.RuntimeVersion}
+ {(userSecretsId is null ? "" : $"#:property UserSecretsId={userSecretsId}")}
+
+ using Microsoft.Extensions.Configuration;
+
+ IConfigurationRoot config = new ConfigurationBuilder()
+ .AddUserSecrets()
+ .Build();
+
+ Console.WriteLine("v1");
+ Console.WriteLine(config.GetDebugView());
+ """;
+
+ var programPath = Path.Join(testInstance.Path, "Program.cs");
+ File.WriteAllText(programPath, code);
+
+ if (useIdArg)
+ {
+ if (userSecretsId == null)
+ {
+ var result = new DotnetCommand(Log, "build", "-getProperty:UserSecretsId", "Program.cs")
+ .WithWorkingDirectory(testInstance.Path)
+ .Execute();
+ result.Should().Pass();
+ userSecretsId = result.StdOut!.Trim();
+ }
+
+ new DotnetCommand(Log, "user-secrets", "set", "MySecret", "MyValue", "--id", userSecretsId)
+ .WithWorkingDirectory(testInstance.Path)
+ .Execute()
+ .Should().Pass();
+ }
+ else
+ {
+ new DotnetCommand(Log, "user-secrets", "set", "MySecret", "MyValue", "--file", "Program.cs")
+ .WithWorkingDirectory(testInstance.Path)
+ .Execute()
+ .Should().Pass();
+ }
+
+ Build(testInstance, BuildLevel.All, expectedOutput: """
+ v1
+ MySecret=MyValue (JsonConfigurationProvider for 'secrets.json' (Optional))
+ """);
+
+ code = code.Replace("v1", "v2");
+ File.WriteAllText(programPath, code);
+
+ Build(testInstance, BuildLevel.Csc, expectedOutput: """
+ v2
+ MySecret=MyValue (JsonConfigurationProvider for 'secrets.json' (Optional))
+ """);
+ }
+
///
/// Verifies that msbuild-based runs use CSC args equivalent to csc-only runs.
/// Can regenerate CSC arguments template in .
@@ -2725,24 +3141,97 @@ 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]");
+
+ // 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]"); // 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" + code);
+
+ 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, BuildLevel.None, expectedOutput: "[MyString, TestValue]"); // note: outdated output (build skipped)
+ 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"), "//v2\n" + s_programReadingEmbeddedResource);
+ File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), "//v3\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]" : "[MyString, TestValue]");
Build(testInstance, BuildLevel.All, ["--no-cache"], expectedOutput: "[MyString, UpdatedValue]");
}
@@ -2970,6 +3459,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()
{
@@ -3025,6 +3535,9 @@ public void CscOnly_AfterMSBuild()
Build(testInstance, BuildLevel.All, expectedOutput: "v4 ");
}
+ ///
+ /// See .
+ ///
[Fact]
public void CscOnly_AfterMSBuild_SpacesInPath()
{
@@ -3055,6 +3568,77 @@ 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 .
+ /// If hard links are enabled, the bin/app.dll and obj/app.dll files are going to be the same,
+ /// so our "copy obj to bin" logic must account for that.
+ ///
+ [Fact]
+ public void CscOnly_AfterMSBuild_HardLinks()
+ {
+ var testInstance = _testAssetsManager.CreateTestDirectory(baseDirectory: OutOfTreeBaseDirectory);
+ var programPath = Path.Join(testInstance.Path, "Program.cs");
+
+ var code = $"""
+ #:property CreateHardLinksForCopyFilesToOutputDirectoryIfPossible=true
+ #:property CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible=true
+ {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);
+
+ code = code.Replace("Hello", "Hi");
+ File.WriteAllText(programPath, code);
+
+ Build(testInstance, BuildLevel.Csc, expectedOutput: "Hi from Program");
+ }
+
+ ///
+ /// See .
+ /// This optimization currently does not support #:project references and hence is disabled if those are present.
+ ///
[Fact]
public void CscOnly_AfterMSBuild_ProjectReferences()
{
@@ -3111,8 +3695,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)
@@ -3156,6 +3740,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()
{
@@ -3231,6 +3818,14 @@ public void Api()
artifacts/$(MSBuildProjectName)artifacts/$(MSBuildProjectName)true
+ false
+ true
+ Exe
+ {ToolsetInfo.CurrentTargetFramework}
+ enable
+ enable
+ true
+ true
@@ -3241,15 +3836,9 @@ public void Api()
- Exe
- enable
- enable
- true
- false
- true
- falsenet11.0preview
+ false$(Features);FileBasedProgram
@@ -3301,6 +3890,14 @@ public void Api_Diagnostic_01()
artifacts/$(MSBuildProjectName)artifacts/$(MSBuildProjectName)true
+ false
+ true
+ Exe
+ {ToolsetInfo.CurrentTargetFramework}
+ enable
+ enable
+ true
+ true
@@ -3310,13 +3907,6 @@ public void Api_Diagnostic_01()
- Exe
- {ToolsetInfo.CurrentTargetFramework}
- enable
- enable
- true
- false
- truefalse$(Features);FileBasedProgram
@@ -3368,6 +3958,14 @@ public void Api_Diagnostic_02()
artifacts/$(MSBuildProjectName)artifacts/$(MSBuildProjectName)true
+ false
+ true
+ Exe
+ {ToolsetInfo.CurrentTargetFramework}
+ enable
+ enable
+ true
+ true
@@ -3377,13 +3975,6 @@ public void Api_Diagnostic_02()
- Exe
- {ToolsetInfo.CurrentTargetFramework}
- enable
- enable
- true
- false
- truefalse$(Features);FileBasedProgram
diff --git a/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs b/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs
index 8ced55de7342..08d323f2cc28 100644
--- a/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs
+++ b/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/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestfromCsproj.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestfromCsproj.cs
index 85d6749e07a5..96b0e9edb73b 100644
--- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTestfromCsproj.cs
+++ b/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/test/dotnet.Tests/CommandTests/Test/TestProgressStateTests.cs b/test/dotnet.Tests/CommandTests/Test/TestProgressStateTests.cs
index 257338656fc3..b55a7f2cdfb4 100644
--- a/test/dotnet.Tests/CommandTests/Test/TestProgressStateTests.cs
+++ b/test/dotnet.Tests/CommandTests/Test/TestProgressStateTests.cs
@@ -18,7 +18,7 @@ public class TestProgressStateTests
public void ReportSkippedTest_MultipleCalls_DifferentInstanceId()
{
var stopwatchMock = new Mock();
- var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object);
+ var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object, isDiscovery: false);
string testUid = "test1";
string instanceA = "instanceA";
string instanceB = "instanceB";
@@ -48,7 +48,7 @@ public void ReportSkippedTest_MultipleCalls_DifferentInstanceId()
public void ReportSkippedTest_RepeatedInstanceAfterRetry_ThrowsInvalidOperationException()
{
var stopwatchMock = new Mock();
- var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object);
+ var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object, isDiscovery: false);
string testUid = "test1";
string instanceA = "instanceA";
string instanceB = "instanceB";
@@ -75,7 +75,7 @@ public void ReportSkippedTest_RepeatedInstanceAfterRetry_ThrowsInvalidOperationE
public void ReportFailedTest_RepeatedCalls_IncrementsFailedTests(int callCount)
{
var stopwatchMock = new Mock();
- var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object);
+ var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object, isDiscovery: false);
state.NotifyHandshake("instance1");
for (int i = 0; i < callCount; i++)
{
@@ -95,7 +95,7 @@ public void ReportFailedTest_RepeatedCalls_IncrementsFailedTests(int callCount)
public void ReportFailedTest_DifferentInstanceId_RetriesFailureAndResetsCount()
{
var stopwatchMock = new Mock();
- var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object);
+ var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object, isDiscovery: false);
state.NotifyHandshake("id1");
state.ReportFailedTest("testUid", "id1");
state.ReportFailedTest("testUid", "id1");
@@ -114,7 +114,7 @@ public void ReportFailedTest_DifferentInstanceId_RetriesFailureAndResetsCount()
public void ReportFailedTest_ReusingOldInstanceId_ThrowsInvalidOperationException()
{
var stopwatchMock = new Mock();
- var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object);
+ var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object, isDiscovery: false);
state.NotifyHandshake("id1");
state.ReportFailedTest("testUid", "id1");
state.NotifyHandshake("id2");
@@ -134,7 +134,7 @@ public void ReportFailedTest_ReusingOldInstanceId_ThrowsInvalidOperationExceptio
public void ReportTest_WithNewInstanceId_ClearsOldReports()
{
var stopwatchMock = new Mock();
- var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object);
+ var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object, isDiscovery: false);
state.NotifyHandshake("id1");
state.ReportFailedTest("testUid", "id1");
state.ReportFailedTest("testUid", "id1");
@@ -154,6 +154,7 @@ public void ReportTest_WithNewInstanceId_ClearsOldReports()
state.SkippedTests.Should().Be(1);
state.RetriedFailedTests.Should().Be(3);
}
+
///
/// Tests that DiscoverTest increments PassedTests and adds the displayName and uid to DiscoveredTests.
///
@@ -173,14 +174,15 @@ public void DiscoverTest_DisplayNameAndUid_AddsEntryAndIncrementsPassedTests(str
assembly: "assembly.dll",
targetFramework: null,
architecture: null,
- stopwatch: stopwatchMock.Object);
+ stopwatch: stopwatchMock.Object,
+ isDiscovery: true);
state.DiscoverTest(displayName, uid);
- state.PassedTests.Should().Be(1);
- state.DiscoveredTests.Count.Should().Be(1);
- state.DiscoveredTests[0].DisplayName.Should().Be(displayName);
- state.DiscoveredTests[0].UID.Should().Be(uid);
+ state.DiscoveredTests.Should().Be(1);
+ state.DiscoveredTestNames.Count.Should().Be(1);
+ state.DiscoveredTestNames[0].DisplayName.Should().Be(displayName);
+ state.DiscoveredTestNames[0].UID.Should().Be(uid);
}
[Fact]
@@ -188,7 +190,7 @@ public void FailedTestRetryShouldShouldShowTheSameTotalCountsInEachRetry()
{
// Tests are retried, total test count stays 3 to give use comparable counts, no matter how many times we retry.
var stopwatchMock = new Mock();
- var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object);
+ var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object, isDiscovery: false);
// First run
state.NotifyHandshake("run1");
@@ -227,7 +229,7 @@ public void FailedTestRetryShouldNotFailTheRunWhenSecondRunProducesLessDynamicTe
{
// This is special test for dynamic tests where we don't know how many tests will be produced in the second run.
var stopwatchMock = new Mock();
- var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object);
+ var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object, isDiscovery: false);
// First run
state.NotifyHandshake("run1");
@@ -259,7 +261,7 @@ public void FailedTestRetryShouldAccountPassedTestsInRetry()
{
// This is special test for dynamic tests where we cannot avoid re-running even non-failing tests from dynamic tests.
var stopwatchMock = new Mock();
- var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object);
+ var state = new TestProgressState(1, "assembly.dll", null, null, stopwatchMock.Object, isDiscovery: false);
// First run
state.NotifyHandshake("run1");
diff --git a/test/dotnet.Tests/CommandTests/Tool/Install/ToolInstallGlobalOrToolPathCommandTests.cs b/test/dotnet.Tests/CommandTests/Tool/Install/ToolInstallGlobalOrToolPathCommandTests.cs
index 8b1f84c62cc8..65c0dd06d35c 100644
--- a/test/dotnet.Tests/CommandTests/Tool/Install/ToolInstallGlobalOrToolPathCommandTests.cs
+++ b/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/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh
index 0e1338dd8889..c6b13b332377 100644
--- a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh
+++ b/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/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1
index b041745522b0..1066fdfe3711 100644
--- a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1
+++ b/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/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh
index a69bd908c3a8..4688c833f62a 100644
--- a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh
+++ b/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" ))' \
@@ -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/test/dotnet.Tests/TelemetryCommonPropertiesTests.cs b/test/dotnet.Tests/TelemetryCommonPropertiesTests.cs
index a77f0bf81765..ae1ced7c696d 100644
--- a/test/dotnet.Tests/TelemetryCommonPropertiesTests.cs
+++ b/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,21 +191,27 @@ 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)
+ if (envVars is not null)
{
- Environment.SetEnvironmentVariable(key, value);
+ 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);
+ }
}
}
}
@@ -215,7 +219,7 @@ public void CanDetectLLMStatusForEnvVars(Dictionary envVars, str
[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 +229,42 @@ public void TelemetryCommonPropertiesShouldContainSessionId(string sessionId)
}
- public static IEnumerable