diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 758fa0d59c44..b3ed9f3ac517 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -31,12 +31,17 @@ Testing: - Test commands in the dogfood shell (e.g., `dnx --help`, `dotnet tool install --help`) - The dogfood script sets up PATH and environment to use the newly built SDK +Investigating PR validation failures: +1. Read the PR and its comments/reviews. Check for references to other PRs or issues where the problem might have already been solved. +2. Use the `ci-analysis` skill (if available) to diagnose build failures. + Output Considerations: - When considering how output should look, solicit advice from baronfel. Localization: - Avoid modifying .xlf files and instead prompt the user to update them using the `/t:UpdateXlf` target on MSBuild. Correctly automatically modified .xlf files have elements with state `needs-review-translation` or `new`. - Consider localizing strings in .resx files when possible. +- When adding a new NETSDK error message in `src/Tasks/Common/Resources/Strings.resx`, assign the next available NETSDK code, append the entry at the end of the file, and update the trailing "latest message added" guard comment. Documentation: - Do not manually edit files under documentation/manpages/sdk as these are generated based on documentation and should not be manually modified. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0fae5021e482..7d6b9a66f3a0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,6 +9,10 @@ updates: labels: - "dependencies" - "dependabot: main" + ignore: + # arcade and helix are updated by the automated codeflow process + - dependency-name: "Microsoft.DotNet.Arcade.Sdk" + - dependency-name: "Microsoft.DotNet.Helix.Sdk" # - package-ecosystem: "nuget" # directory: "/eng/dependabot" diff --git a/.github/workflows/add-servicing-consider-label.yml b/.github/workflows/add-servicing-consider-label.yml new file mode 100644 index 000000000000..1b84e2ebd869 --- /dev/null +++ b/.github/workflows/add-servicing-consider-label.yml @@ -0,0 +1,86 @@ +name: Add Servicing-consider Label to PRs + +on: + # zizmor: ignore[dangerous-triggers] -- no PR code is checked out; only adds a label via API + pull_request_target: + types: [opened, reopened, ready_for_review] + branches: + - 'release/[0-9]*' + +permissions: + contents: read + pull-requests: write + +jobs: + add-servicing-label: + runs-on: ubuntu-latest + # Only run in the dotnet/sdk repository + if: github.repository == 'dotnet/sdk' + + steps: + - name: Add Servicing-consider label if needed + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 + with: + script: | + const pr = context.payload.pull_request; + const prNumber = pr.number; + + // Skip if the PR already has the Servicing-consider or Servicing-approved label + const labels = pr.labels.map(l => l.name); + if (labels.includes('Servicing-consider') || labels.includes('Servicing-approved')) { + console.log('PR already has a servicing label, skipping.'); + return; + } + + // Skip codeflow PRs: inter-branch merge flow and darc subscription PRs. + // Only skip known codeflow bot accounts; other bots (e.g. Dependabot) should + // still receive the label. Backport PRs carry the 'backport' label and are + // also exempt from this skip. + const author = pr.user.login; + const codeflowBots = ['dotnet-maestro[bot]', 'github-actions[bot]', 'dotnet-maestro']; + const isBackport = labels.includes('backport'); + if (codeflowBots.includes(author) && !isBackport) { + console.log(`Skipping codeflow PR authored by bot: ${author}`); + return; + } + + // Skip branding and internal-to-public flow PRs from vseanreesermsft + if (author === 'vseanreesermsft') { + console.log(`Skipping branding/internal-to-public PR authored by: ${author}`); + return; + } + + // Fetch all changed files in the PR (paginated to handle large PRs) + let files = []; + let page = 1; + while (true) { + const { data: pageFiles } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + per_page: 100, + page: page + }); + files = files.concat(pageFiles); + if (pageFiles.length < 100) break; + page++; + } + + // Skip test-only PRs: all changed files are under test/ directories + const isTestOnly = files.length > 0 && files.every(file => + file.filename.startsWith('test/') + ); + + if (isTestOnly) { + console.log('PR only contains test changes, skipping.'); + return; + } + + // Add the Servicing-consider label + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + labels: ['Servicing-consider'] + }); + console.log(`Added Servicing-consider label to PR #${prNumber}.`); diff --git a/.vsts-ci.yml b/.vsts-ci.yml index 3d56a6519a34..c7113b79ad55 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -9,6 +9,14 @@ trigger: - internal/release/* - exp/* +schedules: +- cron: '0 0 * * 0' + displayName: Weekly CodeQL/SDL build + branches: + include: + - main + always: true + pr: branches: include: @@ -91,6 +99,12 @@ extends: - stage: build displayName: Build jobs: + ############### HELIX JOB MONITOR ############### + - ${{ if or(eq(parameters.runTestBuild, true), eq(variables['Build.Reason'], 'PullRequest')) }}: + - template: /eng/common/core-templates/job/helix-job-monitor.yml@self + parameters: + helixAccessToken: $(HelixApiAccessToken) + ############### WINDOWS ############### - template: /eng/pipelines/templates/jobs/sdk-job-matrix.yml@self parameters: @@ -109,7 +123,7 @@ extends: preSteps: - powershell: New-Item -ItemType Directory -Path $(Build.SourcesDirectory)/artifacts/bin -Force displayName: Create artifacts/bin directory - ${{ if and(eq(parameters.runTestBuild, false), ne(variables['Build.Reason'], 'PullRequest')) }}: + ${{ if and(eq(parameters.runTestBuild, false), ne(variables['Build.Reason'], 'PullRequest'), ne(variables['Build.Reason'], 'BatchedCI')) }}: timeoutInMinutes: 180 windowsJobParameterSets: ### OFFICIAL ### @@ -164,7 +178,7 @@ extends: 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')) }}: + ${{ if and(eq(parameters.runTestBuild, false), ne(variables['Build.Reason'], 'PullRequest'), ne(variables['Build.Reason'], 'BatchedCI')) }}: timeoutInMinutes: 90 linuxJobParameterSets: ### OFFICIAL ### @@ -247,7 +261,7 @@ extends: 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')) }}: + ${{ if and(eq(parameters.runTestBuild, false), ne(variables['Build.Reason'], 'PullRequest'), ne(variables['Build.Reason'], 'BatchedCI')) }}: timeoutInMinutes: 90 macOSJobParameterSets: ### OFFICIAL ### diff --git a/.vsts-pr.yml b/.vsts-pr.yml index 0468e1b38e30..e6d1b81a88ec 100644 --- a/.vsts-pr.yml +++ b/.vsts-pr.yml @@ -35,12 +35,6 @@ pr: - src/Installer/* - test/dotnetup.Tests/* -parameters: -- name: enableArm64Job - displayName: Enables the ARM64 job - type: boolean - default: true - variables: - template: /eng/pipelines/templates/variables/sdk-defaults.yml # Variables used: DncEngPublicBuildPool @@ -56,6 +50,9 @@ stages: - stage: build displayName: Build jobs: + ############### HELIX JOB MONITOR ############### + - template: /eng/common/core-templates/job/helix-job-monitor.yml + ############### WINDOWS ############### - template: /eng/pipelines/templates/jobs/sdk-job-matrix.yml@self parameters: @@ -81,20 +78,19 @@ stages: name: Azure Pipelines vmImage: macOS-latest os: macOS - helixTargetQueue: osx.15.amd64.open - ### ARM64 ### - - ${{ if eq(parameters.enableArm64Job, true) }}: + helixTargetQueue: osx.15.arm64.open + ### x64 (CI only) ### + - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - template: /eng/pipelines/templates/jobs/sdk-job-matrix.yml parameters: pool: name: Azure Pipelines vmImage: macOS-latest os: macOS - helixTargetQueue: osx.15.arm64.open + helixTargetQueue: osx.15.amd64.open macOSJobParameterSets: - categoryName: TestBuild - targetArchitecture: arm64 - runtimeIdentifier: osx-arm64 + runtimeIdentifier: osx-x64 ############### DOTNET-FORMAT ############### - template: /eng/dotnet-format/dotnet-format-integration.yml diff --git a/Directory.Build.props b/Directory.Build.props index 567ccc403c7d..0072e1992454 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -75,8 +75,10 @@ enable - - + + false diff --git a/documentation/general/eliminate-duplicate-files.md b/documentation/general/eliminate-duplicate-files.md index 67f1322ff43f..bb3716e11e30 100644 --- a/documentation/general/eliminate-duplicate-files.md +++ b/documentation/general/eliminate-duplicate-files.md @@ -30,6 +30,7 @@ The following data is the result of this analysis using the [SdkLayoutAnalyzer]( The goal is for the vast majority if not all of the components within the SDK to depend on and use the same version of their dependencies. **Notes:** + 1. The baseline measurements in the following tables compare the complete .NET installation (including runtimes, packs, shared frameworks, host, etc.) versus just the SDK directory contents. 1. Standard archive formats (zip and tar) do not automatically deduplicate identical files, each file is compressed independently, even when multiple files have identical content. This means that duplicate files consume space both on disk after extraction and within the compressed archive itself. @@ -145,6 +146,7 @@ While the RPM protocol itself supports hard links, there are known issues in bot Additionally, our current build infrastructure (Arcade) does not support creating RPM packages with hard links ([dotnet/arcade#16453](https://github.com/dotnet/arcade/issues/16453)). Before we can confidently support hard links on Linux, we need to: + 1. Fix the Arcade infrastructure to support creating RPM packages with hard links 2. Test comprehensively on the Linux distributions we target, particularly Azure Linux 3. Work with distribution maintainers to ensure compatibility @@ -153,6 +155,7 @@ Until this work is completed and validated, we will use symbolic links on non-Wi If we find that hard links cannot be used in RPM packages long term, one alternative to consider would be using hard links everywhere except RPM packages, which would continue using symbolic links. However, this approach has trade-offs that would need to be carefully evaluated: + - **Con:** Different link types across acquisition channels adds complexity - **Con:** Distribution maintainers who create RPM packages from our source tarballs would need to translate hard links to symbolic links @@ -162,8 +165,8 @@ A decision on this alternative approach will be made once the RPM packaging inve Hard links are generally preferred because they [offer performance advantages since no extra steps are needed to resolve the file path](https://www.linuxbash.sh/post/symbolic-links-ln-s-vs-hard-links), providing slightly better access time compared to symbolic links which require path resolution. - **Key Benefits of File Links:** + - **No runtime changes required** — Components continue to reference files using their existing paths. Both hard links and symbolic links are transparent to applications. - **Immediate disk savings** — Links reduce disk usage by the size of duplicate files. - **Tarball compatibility** — Tar format natively supports both hard links and symbolic links, preserving space savings in compressed archives. @@ -201,6 +204,7 @@ The existing zip archives will continue to be published with duplicates during t **Phase 2: Migrate Acquisition Channels** In subsequent preview releases, we will migrate the acquisition channels under our control to use Windows tarballs: + - **dotnet-install scripts** ([dotnet/install-scripts](https://github.com/dotnet/install-scripts)) — Update to prefer tarballs on Windows - **Azure DevOps .NET install task** ([microsoft/azure-pipelines-tasks](https://github.com/microsoft/azure-pipelines-tasks)) — Add tarball support for Windows agents - **GitHub Actions setup-dotnet** ([actions/setup-dotnet](https://github.com/actions/setup-dotnet)) — Add tarball extraction support for Windows @@ -265,6 +269,7 @@ Tests will be created to ensure: A proof of concept for link-based deduplication was implemented, demonstrating the viability and effectiveness of the approach: **Implementation Details:** + - A new MSBuild task `DeduplicateFilesWithHardLinks` was created to identify and replace duplicate files with links during SDK layout generation - Files are hashed to identify duplicates - The POC initially used hard links; the production implementation will use platform-specific link types (hard links on Windows, symbolic links on Linux/macOS) @@ -272,6 +277,7 @@ A proof of concept for link-based deduplication was implemented, demonstrating t **Space Savings:** In a Linux x64 development build of .NET 11.0 SDK, the link-based approach achieved: + - 131 MB reduction in disk size - 61 MB reduction in archive size @@ -312,6 +318,7 @@ The analysis categorizes these groups as follows: **Linux x64 (10.0.100):** Group Categorization: + - Groups differing by Core vs FX: 228 - Groups with different FX versions: 3 - Groups with different Core versions: 1 @@ -320,6 +327,7 @@ Group Categorization: - Groups with NetStandard + Core: 30 Potential Savings (if duplicates were eliminated): + - Different FX versions (keep lowest): 1.9 MB - Different Core versions (keep lowest): 0.1 MB - NetStandard + NetFx (keep NetStandard): 0.9 MB @@ -354,6 +362,7 @@ This represents content that should be trimmed out entirely as it serves no purp In other cases, we ship content to support cross-platform development scenarios—for example, Windows-specific assemblies included in Linux SDKs to enable cross-compilation or multi-targeting scenarios. While this content does serve a purpose, it should be analyzed case-by-case to determine whether it should: + - Ship in-box as part of the core SDK experience - Be available as optional packages that can be dynamically acquired when needed @@ -365,6 +374,12 @@ Both of these content placement issues are outside the scope of the duplicate el However, they will likely be surfaced and made more visible as part of this effort. When identified, independent issues will be logged to address these concerns separately. +### Windows Containers + +Windows containers do not support hard links, which blocks adoption of this feature for Windows container images. +The impact of this limitation is modest: Windows containers have significantly fewer supported versions/SKUs than Linux, and Windows base image updates occur only once per month (Patch Tuesday), resulting in far fewer image rebuilds. +As a result, the potential savings for Windows container images would be an order of magnitude less than Linux. + ## Related - [Visual Studio de-duplication effort](https://microsoft.sharepoint.com/:w:/s/b3f10b15-fb59-4650-957a-2c632aa943ba/IQBR2aXv7jC8RatIyxJJNPCeAQxjDmLii-R65o0yUvOJatk?e=IcnsAG) @@ -471,3 +486,43 @@ While the shared assembly location approach offers theoretical benefits in terms 5. **Implementation Cost:** High development and maintenance burden compared to filesystem-level deduplication. The hard link approach was selected because it achieves the same disk and archive size benefits without requiring changes to component loading logic or risking behavioral changes in sensitive toolchain components. + +## Appendix: Docker Image Savings Analysis + +This section quantifies the downstream impact of deduplication on .NET Docker images. +The estimates use .NET 10 as a representative single release to project per-release savings. +The "In-Support" columns show the projected combined impact once three in-support versions all include this feature. +The "All" columns show cumulative totals across all SDK images and pulls (in-support and EOL), illustrating savings that accrue over time. + +### Linux SDK Archive Size Reduction + +As of .NET 11.0 Preview 4, the Linux SDK archive is **56 MB smaller** as a result of this work. + +### Linux SDK Image Pull Bandwidth Savings + +| .NET 10 Pulls/Wk | In-Support Pulls/Wk | All Pulls/Wk | .NET 10 Saved (TB wk / yr) | In-Support Saved (TB wk / yr) | All Saved (TB wk / yr) | +|------------------|---------------------|--------------|----------------------------|-------------------------------|------------------------| +| 147,000 | 485,400 | 630,000 | 7.9 / 408.2 | 25.9 / 1348.0 | 33.9 / 1749.6 | + +### Linux SDK Image Storage Savings + +| New .NET 10 Images/Mo | New In-Support Images/Mo | All Images | .NET 10 Saved (GB mo / yr) | In-Support Saved (GB mo / yr) | All Saved (GB) | +|-----------------------|--------------------------|------------|----------------------------|-------------------------------|----------------| +| 42.6 | 130.5 | 26,866 | 2.3 / 27.6 | 7.1 / 85.6 | 1,469.2 | + +--- + +1 "All" columns represent all SDK images ever published to MCR and all SDK image pulls per week, regardless of whether the .NET version is currently in support or end-of-life. + +2 New images per month are driven by multiple sources: .NET servicing releases (Patch Tuesday) and base image updates. .NET images are rebuilt whenever an underlying base image (e.g., Ubuntu, Alpine) is updated. + +3 Assuming saved storage is billed at the [ACR](https://azure.microsoft.com/en-us/pricing/details/container-registry/) additional storage rate of $0.00334/GB/day, the in-support storage savings of 7.1 GB/month translate to approximately **$0.71/month**. If every Linux SDK image ever shipped had included this feature, the total cumulative savings of ~1.5 TB would translate to roughly **$147/month**. + +### Key Takeaways + +- Over the .NET 10 LTS three-year support period, this saves approximately **1,224.6 TB** in bandwidth (408.2 TB/yr x 3) and **82.8 GB** in storage (27.6 GB/yr x 3). +Those savings don't count previews, usage increase when the previous LTS (8.0) reaches end-of-life or pulls after EOL. +- **Bandwidth savings are significant in absolute terms**, over 1,350 TB/year for in-support versions at 630,000 pulls per week. +This is modest relative to the scale at which Azure operates, as indicated by its pricing. +- **Storage savings are negligible.** Even if every Linux SDK image ever shipped had included this feature, the cumulative savings would be ~1.5 TB. +- The primary value is **customer-facing**: every Linux SDK image pull is 56 MB smaller, resulting in faster downloads and reduced storage/higher density for users. diff --git a/documentation/project-docs/SDK-PR-guide.md b/documentation/project-docs/SDK-PR-guide.md index efa48c2a17dd..76dbf5555975 100644 --- a/documentation/project-docs/SDK-PR-guide.md +++ b/documentation/project-docs/SDK-PR-guide.md @@ -40,6 +40,11 @@ The .NET 8 and .NET 9 servicing branches are locked from the time of code comple ### Tactics approval Even releases that are in lockdown can still take changes as long as they are approved and the final build isn't complete. To bring a change through tactics, mark it with the label `servicing-consider` and update the description to include 5 sections (Description, Customer Impact, Regression?, Risk, Testing). See previously approved bugs for examples by looking for the [servicing-approved](https://github.com/dotnet/sdk/pulls?q=is%3Apr+label%3AServicing-approved+is%3Aclosed) label. +Any PR that targets a version-like servicing branch (`release/[0-9]*`, e.g. `release/8.0.4xx`, `release/10.0`) and is not a codeflow PR or a test-only change will automatically have the `Servicing-consider` label applied by the [add-servicing-consider-label](https://github.com/dotnet/sdk/blob/main/.github/workflows/add-servicing-consider-label.yml) workflow. This prevents accidental merging of new features without tactics approval. The following PR types are exempt from automatic labeling: +- PRs from automated codeflow bots (inter-branch merge flow, darc subscriptions) — but **not** backport PRs, which are also bot-authored and do require servicing approval. +- PRs that only modify files in the `test/` directory. +- PRs authored by `vseanreesermsft` (branding and internal-to-public flow). + For servicing changes to other repos like MSBuild and NuGet, we recommend getting approval from tactics before the PR is merged. For codeflow, we do not gate codeflow on approvals as many codeflows are just infra work that doesn't require approval. Separating those out would add additional complexity we want to avoid. Once your bug is ready for approval (has sign-off and the template details in the description), you can come to tactics for live approval or send email to the tactics alias. If you get tactics approval offline from the .NET QB, remove the `servicing-consider` label, add the `servicing-approved` label, set the milestone to match the runtime release this ships with, and merge if the branch is open. diff --git a/dotnet-tools.json b/dotnet-tools.json index b0e38abdace3..d452097eb287 100644 --- a/dotnet-tools.json +++ b/dotnet-tools.json @@ -1,5 +1,12 @@ { "version": 1, "isRoot": true, - "tools": {} + "tools": { + "microsoft.dotnet.helix.jobmonitor": { + "version": "11.0.0-beta.26303.111", + "commands": [ + "dotnet-helix-job-monitor" + ] + } + } } \ No newline at end of file diff --git a/eng/Build.props b/eng/Build.props index 9c20ef3cf4a5..25737d3a05c5 100644 --- a/eng/Build.props +++ b/eng/Build.props @@ -4,13 +4,14 @@ - + diff --git a/eng/build.ps1 b/eng/build.ps1 index 562372432565..8e1929411ffa 100644 --- a/eng/build.ps1 +++ b/eng/build.ps1 @@ -36,9 +36,9 @@ if ($test) { $arguments += " -test" } if ($pack) { $arguments += " -pack" if (-not $skipCrossgen) { $arguments += " /p:SkipUsingCrossgen=false" } - if (-not $skipInstallers) { $arguments += " /p:SkipBuildingInstallers=false" } + if (-not $skipInstallers) { $arguments += " /p:SkipBuildingInstallers=false /p:SkipBuildingArchives=false" } } else { - $arguments += " /p:SkipUsingCrossgen=true /p:SkipBuildingInstallers=true" + $arguments += " /p:SkipUsingCrossgen=true /p:SkipBuildingInstallers=true /p:SkipBuildingArchives=true " } if ($properties) { $arguments += " " + ($properties -join " ") } diff --git a/eng/configure-toolset.ps1 b/eng/configure-toolset.ps1 index 1b695da8b864..3a26bc2a2c42 100644 --- a/eng/configure-toolset.ps1 +++ b/eng/configure-toolset.ps1 @@ -4,14 +4,8 @@ $script:useInstalledDotNetCli = $false -function Test-NativeProcessArchitectureMismatch() { - try { - return [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -ne [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture - } - catch { - return $false - } -} +# Shared dotnetup acquisition helpers (architecture detection, cache freshness, download). +. (Join-Path $PSScriptRoot 'dotnetup-shared.ps1') # Pre-install the bootstrap SDK pinned in global.json using dotnetup into the # repo-local .dotnet directory that arcade's InitializeDotnetCli will pick up. @@ -36,29 +30,13 @@ function InstallBootstrapSdkWithDotnetup() { $dotnetupDir = Join-Path $PSScriptRoot 'dotnetup' $dotnetupExe = Join-Path $dotnetupDir (GetExecutableFileName 'dotnetup') - # Re-download dotnetup at most once every 24 hours to avoid unnecessary network calls. - $skipDownload = $false - if (Test-Path $dotnetupExe) { - $age = (Get-Date) - (Get-Item $dotnetupExe).LastWriteTime - if ($age.TotalHours -lt 24) { - Write-Host "dotnetup binary is less than 24 hours old; skipping re-download." -ForegroundColor DarkGray - $skipDownload = $true + if (-not (Test-ShouldUseCachedDotnetup $dotnetupExe)) { + try { + Install-DotnetupFromAkaMs $dotnetupDir } - } - - if ($skipDownload -and (Test-NativeProcessArchitectureMismatch)) { - Write-Host "Native architecture differs from process architecture; re-downloading dotnetup for the native architecture." -ForegroundColor DarkGray - $skipDownload = $false - } - - if (-not $skipDownload) { - # Seed $LASTEXITCODE so strict mode can read it if the called script - # short-circuits without invoking a native process. - if (-not (Test-Path Variable:LASTEXITCODE)) { $global:LASTEXITCODE = 0 } - & (Join-Path $RepoRoot 'scripts\get-dotnetup.ps1') -InstallDir $dotnetupDir - if ($LASTEXITCODE -ne 0) { - Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Failed to acquire dotnetup (exit code '$LASTEXITCODE')." - ExitWithExitCode $LASTEXITCODE + catch { + Write-Host "Failed to acquire dotnetup: $($_.Exception.Message). Will fall back to standard dotnet-install script." -ForegroundColor Yellow + return } } diff --git a/eng/configure-toolset.sh b/eng/configure-toolset.sh index 7dcace829a1f..4821ef6d8b71 100644 --- a/eng/configure-toolset.sh +++ b/eng/configure-toolset.sh @@ -4,23 +4,8 @@ useInstalledDotNetCli="false" -function GetNativeMachineArchitecture { - if [[ "$(uname)" == "Darwin" ]] && [[ "$(sysctl -n hw.optional.arm64 2>/dev/null)" == "1" ]]; then - echo "arm64" - return - fi - case "$(uname -m)" in - arm64|aarch64) echo "arm64" ;; - amd64|x86_64) echo "x64" ;; - armv*l) echo "arm" ;; - i[3-6]86) echo "x86" ;; - *) echo "x64" ;; - esac -} - -function IsRunningUnderRosettaOnArm64Mac { - [[ "$(uname)" == "Darwin" && "$(GetNativeMachineArchitecture)" == "arm64" && "$(uname -m)" == "x86_64" ]] -} +# Shared dotnetup acquisition helpers (architecture detection, cache freshness, download). +. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/dotnetup-shared.sh" # Pre-install the bootstrap SDK pinned in global.json using dotnetup into the # repo-local .dotnet directory that arcade's InitializeDotNetCli will pick up. @@ -64,28 +49,8 @@ function InstallBootstrapSdkWithDotnetup { local dotnetup_dir="$script_dir/dotnetup" local dotnetup_exe="$dotnetup_dir/dotnetup" - # Re-download dotnetup at most once every 24 hours to avoid unnecessary network calls. - local skip_download=false - if [[ -f "$dotnetup_exe" ]]; then - local current_time - current_time=$(date +%s) - local file_time - file_time=$(stat -c %Y "$dotnetup_exe" 2>/dev/null || stat -f %m "$dotnetup_exe" 2>/dev/null || echo 0) - local age_seconds=$((current_time - file_time)) - if [[ $age_seconds -lt 86400 ]]; then - echo "dotnetup binary is less than 24 hours old; skipping re-download." - skip_download=true - fi - fi - - if [[ "$skip_download" == true ]] && IsRunningUnderRosettaOnArm64Mac; then - echo "Running under Rosetta 2 on arm64 macOS; re-downloading dotnetup for the native architecture." - skip_download=false - fi - - if [[ "$skip_download" != true ]]; then - # build.sh runs under `set -e`; guard so we can emit a diagnostic. - if ! "$repo_root/scripts/get-dotnetup.sh" --install-dir "$dotnetup_dir"; then + if ! ShouldUseCachedDotnetup "$dotnetup_exe"; then + if ! AcquireDotnetup "$dotnetup_dir"; then Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to acquire dotnetup." ExitWithExitCode 1 fi diff --git a/eng/dotnetup-shared.ps1 b/eng/dotnetup-shared.ps1 new file mode 100644 index 000000000000..0c47bcc74cb7 --- /dev/null +++ b/eng/dotnetup-shared.ps1 @@ -0,0 +1,109 @@ +# Shared helpers for acquiring dotnetup, dot-sourced by both +# eng/configure-toolset.ps1 (bootstrap SDK install) and eng/restore-toolset.ps1 +# (test runtime install). This file only defines functions; it has no top-level +# side effects so it is safe to dot-source multiple times. + +# General SDK build helpers (Get-NativeMachineArchitecture, etc.). +. (Join-Path $PSScriptRoot 'sdk-tools.ps1') + +# Returns $true when an already-downloaded dotnetup binary at $DotnetupExe is +# recent enough (<24h old) and its architecture matches the native machine, so the +# download can be skipped. Returns $false when dotnetup should be (re)downloaded. +function Test-ShouldUseCachedDotnetup([string]$DotnetupExe) { + if (-not (Test-Path $DotnetupExe)) { + return $false + } + + # Re-download dotnetup at most once every 24 hours to avoid unnecessary network calls. + $age = (Get-Date) - (Get-Item $DotnetupExe).LastWriteTime + if ($age.TotalHours -ge 24) { + return $false + } + Write-Host "dotnetup binary is less than 24 hours old; skipping re-download." -ForegroundColor DarkGray + + # dotnetup installs runtimes for its own process architecture, so a cached + # binary downloaded under emulation (process arch != native arch) would install + # the wrong runtimes. Re-download when the architectures differ. + if ((Get-NativeMachineArchitecture) -ne (Get-ProcessMachineArchitecture)) { + Write-Host "Native architecture differs from process architecture; re-downloading dotnetup for the native architecture." -ForegroundColor DarkGray + return $false + } + + return $true +} + +# Runs a PowerShell script in a SEPARATE PowerShell process so that an 'exit' +# inside it cannot terminate this build host and bypass the caller's try/catch. +# Uses the current host's own executable to keep pwsh / Windows PowerShell 5.1 +# parity. Throws on non-zero exit code. +function Invoke-GetDotnetupScript([string]$ScriptPath, [string]$InstallDir, [string]$ErrorLabel) { + $psExe = (Get-Process -Id $PID).Path + if (-not $psExe) { + $psExeName = if ($PSVersionTable.PSEdition -eq 'Core') { 'pwsh' } else { 'powershell' } + $psExe = Join-Path $PSHOME $psExeName + } + if (-not (Test-Path Variable:LASTEXITCODE)) { $global:LASTEXITCODE = 0 } + + # Temporarily set ErrorActionPreference to Continue so that stderr output + # from the child process does not become a terminating error (the parent + # shell inherits 'Stop' from eng/common/tools.ps1). We rely on + # $LASTEXITCODE for error detection instead. + $prevEAP = $ErrorActionPreference + try { + $ErrorActionPreference = 'Continue' + & $psExe -NoProfile -ExecutionPolicy Bypass -File $ScriptPath -InstallDir $InstallDir + } + finally { + $ErrorActionPreference = $prevEAP + } + + if ($LASTEXITCODE -ne 0) { throw "$ErrorLabel exited with code $LASTEXITCODE." } +} + +# Downloads the public dotnetup installer from aka.ms +# (https://aka.ms/dotnetup/get-dotnetup.ps1) and runs it to install dotnetup into +# $DotnetupDir. Throws on failure so callers can choose how to react. +# +# If a local get-dotnetup.ps1 script exists in the repo (scripts/get-dotnetup.ps1), +# it is used directly instead of downloading from aka.ms. This supports branches +# (e.g. release/dnup) that carry the script locally and avoids merge conflicts +# when code flows between branches with and without the local script. +function Install-DotnetupFromAkaMs([string]$DotnetupDir) { + $repoRoot = (Get-Item $PSScriptRoot).Parent.FullName + $localGetter = Join-Path (Join-Path $repoRoot 'scripts') 'get-dotnetup.ps1' + + # Prefer the repo-local script when available (e.g. on release/dnup). + if (Test-Path $localGetter) { + Write-Host "Using local get-dotnetup.ps1 from '$localGetter'." -ForegroundColor DarkGray + Invoke-GetDotnetupScript -ScriptPath $localGetter -InstallDir $DotnetupDir -ErrorLabel "Local get-dotnetup.ps1" + return + } + + $getterUrl = 'https://aka.ms/dotnetup/get-dotnetup.ps1' + $getterScript = Join-Path ([System.IO.Path]::GetTempPath()) ("get-dotnetup-{0}.ps1" -f [System.IO.Path]::GetRandomFileName()) + + # Download the installer with retry/backoff. Invoke-WebRequest's built-in + # -MaximumRetryCount is unavailable on Windows PowerShell 5.1, so retry manually. + $maxAttempts = 3 + for ($attempt = 1; $true; $attempt++) { + try { + Invoke-WebRequest -Uri $getterUrl -OutFile $getterScript -UseBasicParsing + break + } + catch { + if ($attempt -ge $maxAttempts) { + throw "Failed to download dotnetup installer from $getterUrl after $maxAttempts attempts: $($_.Exception.Message)" + } + $delaySeconds = [Math]::Pow(2, $attempt) + Write-Host "Download of dotnetup installer failed (attempt $attempt of $maxAttempts): $($_.Exception.Message). Retrying in $delaySeconds seconds..." -ForegroundColor Yellow + Start-Sleep -Seconds $delaySeconds + } + } + + try { + Invoke-GetDotnetupScript -ScriptPath $getterScript -InstallDir $DotnetupDir -ErrorLabel "get-dotnetup.ps1" + } + finally { + Remove-Item $getterScript -Force -ErrorAction SilentlyContinue + } +} diff --git a/eng/dotnetup-shared.sh b/eng/dotnetup-shared.sh new file mode 100644 index 000000000000..55c711dcbff0 --- /dev/null +++ b/eng/dotnetup-shared.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +# Shared helpers for acquiring dotnetup, sourced by both eng/configure-toolset.sh +# (bootstrap SDK install) and eng/restore-toolset.sh (test runtime install). +# This file only defines functions; it has no top-level side effects so it is +# safe to source multiple times. + +# General SDK build helpers (GetNativeMachineArchitecture, etc.). +. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/sdk-tools.sh" + +# Returns success (0) when an already-downloaded dotnetup binary at $1 is recent +# enough (<24h old) and architecturally compatible with the native machine, so the +# download can be skipped. Returns non-zero when dotnetup should be (re)downloaded. +function ShouldUseCachedDotnetup { + local dotnetup_exe=$1 + [[ -f "$dotnetup_exe" ]] || return 1 + + # Re-download dotnetup at most once every 24 hours to avoid unnecessary network calls. + local current_time file_time age_seconds + current_time=$(date +%s) + file_time=$(stat -c %Y "$dotnetup_exe" 2>/dev/null || stat -f %m "$dotnetup_exe" 2>/dev/null || echo 0) + age_seconds=$((current_time - file_time)) + if [[ $age_seconds -ge 86400 ]]; then + return 1 + fi + echo "dotnetup binary is less than 24 hours old; skipping re-download." + + # dotnetup installs runtimes for its own process architecture, so a cached + # binary of the wrong architecture (e.g. an x64 dotnetup left on a reused + # arm64 agent, or one downloaded under Rosetta 2) would install the wrong + # runtimes. Verify the cached binary's actual architecture against the native + # architecture and re-download on mismatch rather than trusting uname. + if [[ "$(uname)" == "Darwin" ]]; then + local native_arch cached_arch="" + native_arch="$(GetNativeMachineArchitecture)" + if file "$dotnetup_exe" 2>/dev/null | grep -q 'arm64'; then + cached_arch="arm64" + elif file "$dotnetup_exe" 2>/dev/null | grep -q 'x86_64'; then + cached_arch="x64" + fi + if [[ -n "$cached_arch" && "$cached_arch" != "$native_arch" ]]; then + echo "Cached dotnetup architecture ($cached_arch) does not match native architecture ($native_arch); re-downloading." + return 1 + fi + fi + + return 0 +} + +# Downloads the public dotnetup installer from aka.ms +# (https://aka.ms/dotnetup/get-dotnetup.sh) and runs it to install dotnetup into +# the directory given by $1. Returns non-zero on failure. Callers run under +# `set -e`, so invoke via `if ! AcquireDotnetup ...; then` to handle failure. +# +# If a local get-dotnetup.sh script exists in the repo (scripts/get-dotnetup.sh), +# it is used directly instead of downloading from aka.ms. This supports branches +# (e.g. release/dnup) that carry the script locally and avoids merge conflicts +# when code flows between branches with and without the local script. +function AcquireDotnetup { + local dotnetup_dir=$1 + local script_dir + script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + local repo_root + repo_root="$(cd "$script_dir/.." && pwd)" + local local_getter="$repo_root/scripts/get-dotnetup.sh" + + # Prefer the repo-local script when available (e.g. on release/dnup). + if [[ -f "$local_getter" ]]; then + echo "Using local get-dotnetup.sh from '$local_getter'." + bash "$local_getter" --install-dir "$dotnetup_dir" + return $? + fi + + local getter_url="https://aka.ms/dotnetup/get-dotnetup.sh" + local getter_script + # Use an explicit template: bare `mktemp` is not portable because BSD/macOS + # mktemp requires a template (or -t prefix) and errors without one. + getter_script="$(mktemp "${TMPDIR:-/tmp}/get-dotnetup.XXXXXX")" + + local downloaded=false + if command -v curl > /dev/null 2>&1; then + if curl -fsSL --retry 3 "$getter_url" -o "$getter_script"; then downloaded=true; fi + elif command -v wget > /dev/null 2>&1; then + if wget -q --tries=3 -O "$getter_script" "$getter_url"; then downloaded=true; fi + else + echo "Cannot download dotnetup: neither 'curl' nor 'wget' is available on PATH. Install one of them to acquire dotnetup." >&2 + fi + + local result=0 + if [[ "$downloaded" != true ]] || ! bash "$getter_script" --install-dir "$dotnetup_dir"; then + result=1 + fi + + rm -f "$getter_script" + return $result +} diff --git a/eng/pipelines/templates/jobs/sdk-build.yml b/eng/pipelines/templates/jobs/sdk-build.yml index 38f19fa26b28..e2d23bedc9f9 100644 --- a/eng/pipelines/templates/jobs/sdk-build.yml +++ b/eng/pipelines/templates/jobs/sdk-build.yml @@ -30,12 +30,8 @@ parameters: runtimeSourceProperties: '' officialBuildProperties: '' downloadManifestMsiPackages: false - # Lets a build be scoped to a specific project or solution, for example by setting - # this to `/p:Projects=$(Build.SourcesDirectory)/dotnetup.slnf` - projectsArgument: '' ### ARCADE ### preSteps: [] - enableMicrobuildForMacAndLinux: false jobs: - template: /eng/common/${{ parameters.oneESCompat.templateFolderName }}/job/job.yml @@ -52,7 +48,6 @@ jobs: helixRepo: dotnet/sdk timeoutInMinutes: ${{ parameters.timeoutInMinutes }} enableMicrobuild: true - enableMicrobuildForMacAndLinux: ${{ parameters.enableMicrobuildForMacAndLinux }} enablePublishBuildAssets: true enableTelemetry: true enablePublishUsingPipelines: true @@ -102,7 +97,6 @@ jobs: /p:EnableDefaultArtifacts=${{ parameters.enableDefaultArtifacts }} /p:TargetArchitecture=${{ parameters.targetArchitecture }} /p:PgoInstrument=${{ parameters.pgoInstrument }} - ${{ parameters.projectsArgument }} ${{ parameters.runtimeSourceProperties }} ${{ parameters.officialBuildProperties }} /p:DotNetSignType=$(_SignType) /p:TeamName=$(_TeamName) @@ -127,7 +121,6 @@ jobs: /p:TargetArchitecture=${{ parameters.targetArchitecture }} \ /p:PgoInstrument=${{ parameters.pgoInstrument }} \ /p:TargetRid=${{ parameters.runtimeIdentifier }} \ - ${{ parameters.projectsArgument }} \ ${{ parameters.osProperties }} \ ${{ parameters.runtimeSourceProperties }} \ ${{ parameters.officialBuildProperties }} \ @@ -137,21 +130,10 @@ jobs: BuildConfig: $(buildConfiguration) OPENSSL_ENABLE_SHA1_SIGNATURES: 1 MSBUILDALWAYSRETRY: true - # Required by the MicroBuild signing plugin to acquire a federated - # token for ESRP. AzDO exposes System.AccessToken automatically to - # script processes on Windows agents but not on Linux/macOS, so the - # SignFiles task fails with "Access token is not available" without - # this env var. - SYSTEM_ACCESSTOKEN: $(System.AccessToken) TARGET_ARCHITECTURE: ${{ parameters.targetArchitecture }} ############### TESTING ############### - ${{ if eq(parameters.runTests, true) }}: - - ${{ if eq(parameters.runAoTTests, true) }}: - # For the reason this is here, see: https://github.com/dotnet/sdk/issues/22655 - - 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') }}: @@ -163,9 +145,9 @@ jobs: /p:TargetArchitecture=${{ parameters.targetArchitecture }} ${{ parameters.runtimeSourceProperties }} /p:CustomHelixTargetQueue=${{ parameters.helixTargetQueue }} + /p:EnableHelixJobMonitor=true /bl:$(Build.SourcesDirectory)/artifacts/log/$(buildConfiguration)/${{ parameters.categoryName }}Tests.binlog - displayName: 🟣 Run ${{ parameters.categoryName }} Tests - condition: succeeded() + displayName: 🟣 Queue Tests env: # Required by Arcade for running in Helix. SYSTEM_ACCESSTOKEN: $(System.AccessToken) @@ -187,9 +169,9 @@ jobs: ${{ parameters.osProperties }} ${{ parameters.runtimeSourceProperties }} /p:CustomHelixTargetQueue=${{ parameters.helixTargetQueue }}${{ parameters.helixTargetContainer }} + /p:EnableHelixJobMonitor=true /bl:$(Build.SourcesDirectory)/artifacts/log/$(buildConfiguration)/${{ parameters.categoryName }}Tests.binlog - displayName: 🟣 Run ${{ parameters.categoryName }} Tests - condition: succeeded() + displayName: 🟣 Queue Tests env: # Required by Arcade for running in Helix. SYSTEM_ACCESSTOKEN: $(System.AccessToken) @@ -236,7 +218,15 @@ jobs: PathtoPublish: $(Build.ArtifactStagingDirectory) # This is the job name, but because of "legacy reasons", both Agent.JobName and System.JobName are not the actual job name. # See: https://developercommunity.visualstudio.com/t/systemjobname-seems-to-be-incorrectly-assigned-and/1209736#TPIN-N1211828 - ArtifactName: $(System.PhaseName) + ArtifactName: $(System.PhaseName)_Logs publishLocation: Container continueOnError: true condition: always() + + - task: ${{ parameters.oneESCompat.publishTaskPrefix }}PublishPipelineArtifact@1 + displayName: 🟣 Publish Built Assets + inputs: + targetPath: $(Build.SourcesDirectory)/artifacts/packages/$(buildConfiguration)/Shipping + artifactName: $(System.PhaseName)_Assets + continueOnError: true + condition: not(canceled()) diff --git a/eng/pipelines/templates/jobs/sdk-job-matrix.yml b/eng/pipelines/templates/jobs/sdk-job-matrix.yml index 93718485e2db..31d1404aae0b 100644 --- a/eng/pipelines/templates/jobs/sdk-job-matrix.yml +++ b/eng/pipelines/templates/jobs/sdk-job-matrix.yml @@ -29,10 +29,12 @@ parameters: ### MACOS ### macOSJobParameterSets: - categoryName: TestBuild - runtimeIdentifier: osx-x64 + targetArchitecture: arm64 + runtimeIdentifier: osx-arm64 - categoryName: AoT runAoTTests: true - runtimeIdentifier: osx-x64 + targetArchitecture: arm64 + runtimeIdentifier: osx-arm64 jobs: ### ONELOCBUILD ### diff --git a/eng/restore-toolset.ps1 b/eng/restore-toolset.ps1 index 236720a16e76..12f8be7c5e8b 100644 --- a/eng/restore-toolset.ps1 +++ b/eng/restore-toolset.ps1 @@ -1,42 +1,5 @@ -# Detect native OS architecture, which may differ from the process architecture -# (e.g., x64 process running on ARM64 Windows via emulation). -function Get-NativeMachineArchitecture { - try { - $osArch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture - if ($osArch -eq [System.Runtime.InteropServices.Architecture]::Arm64) { - return "arm64" - } - if ($osArch -eq [System.Runtime.InteropServices.Architecture]::X86) { - return "x86" - } - if ($osArch -eq [System.Runtime.InteropServices.Architecture]::Arm) { - return "arm" - } - } - catch { - # Fallback for environments where RuntimeInformation is unavailable - } - return "x64" -} - -function Get-ProcessMachineArchitecture { - try { - $processArch = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture - if ($processArch -eq [System.Runtime.InteropServices.Architecture]::Arm64) { - return "arm64" - } - if ($processArch -eq [System.Runtime.InteropServices.Architecture]::X86) { - return "x86" - } - if ($processArch -eq [System.Runtime.InteropServices.Architecture]::Arm) { - return "arm" - } - } - catch { - # Fallback for environments where RuntimeInformation is unavailable - } - return "x64" -} +# Shared dotnetup acquisition helpers (architecture detection, cache freshness, download). +. (Join-Path $PSScriptRoot 'dotnetup-shared.ps1') function Get-DotNetInstallFallbackArchitecture { if (-not [string]::IsNullOrEmpty($env:TARGET_ARCHITECTURE)) { @@ -244,29 +207,12 @@ function InstallDotNetSharedFrameworks([string[]]$runtimeSpecs, [string]$archite $dotnetupDir = Join-Path $PSScriptRoot "dotnetup" $dotnetupExe = Join-Path $dotnetupDir (GetExecutableFileName "dotnetup") - # Re-download dotnetup at most once every 24 hours to avoid unnecessary network calls. - $skipDownload = $false - if (Test-Path $dotnetupExe) { - $age = (Get-Date) - (Get-Item $dotnetupExe).LastWriteTime - if ($age.TotalHours -lt 24) { - Write-Host "dotnetup binary is less than 24 hours old; skipping re-download." -ForegroundColor DarkGray - $skipDownload = $true + if (-not (Test-ShouldUseCachedDotnetup $dotnetupExe)) { + try { + Install-DotnetupFromAkaMs $dotnetupDir } - } - - if ($skipDownload -and ((Get-NativeMachineArchitecture) -ne (Get-ProcessMachineArchitecture))) { - Write-Host "Native architecture differs from process architecture; re-downloading dotnetup for the native architecture." -ForegroundColor DarkGray - $skipDownload = $false - } - - if (-not $skipDownload) { - # Acquire the latest dotnetup daily build using the in-repo install script. - # get-dotnetup.ps1 may short-circuit without invoking a native process, - # leaving $LASTEXITCODE unset; seed it so strict mode can read it. - if (-not (Test-Path Variable:LASTEXITCODE)) { $global:LASTEXITCODE = 0 } - & (Join-Path $RepoRoot "scripts\get-dotnetup.ps1") -InstallDir $dotnetupDir - if ($lastExitCode -ne 0) { - Write-Host "Failed to acquire dotnetup (exit code '$lastExitCode'); falling back to dotnet install script." -ForegroundColor Yellow + catch { + Write-Host "Failed to acquire dotnetup ($($_.Exception.Message)); falling back to dotnet install script." -ForegroundColor Yellow InstallDotNetSharedFrameworksWithInstallScript -RuntimeSpecs $runtimeSpecsToInstall -DotNetRoot $dotnetRoot -Architecture $architecture return } diff --git a/eng/restore-toolset.sh b/eng/restore-toolset.sh index 36513102b2ca..c25a2dee59d3 100755 --- a/eng/restore-toolset.sh +++ b/eng/restore-toolset.sh @@ -1,20 +1,7 @@ #!/usr/bin/env bash -# Detect native machine architecture, handling macOS Rosetta 2 -# where uname -m may report x86_64 on arm64 hardware. -function GetNativeMachineArchitecture { - if [[ "$(uname)" == "Darwin" ]] && [[ "$(sysctl -n hw.optional.arm64 2>/dev/null)" == "1" ]]; then - echo "arm64" - return - fi - case "$(uname -m)" in - arm64|aarch64) echo "arm64" ;; - amd64|x86_64) echo "x64" ;; - armv*l) echo "arm" ;; - i[3-6]86) echo "x86" ;; - *) echo "x64" ;; - esac -} +# Shared dotnetup acquisition helpers (architecture detection, cache freshness, download). +. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/dotnetup-shared.sh" function InitializeCustomSDKToolset { if [[ "$restore" != true ]]; then @@ -129,46 +116,8 @@ function InstallDotNetSharedFrameworks { local dotnetup_dir="$script_dir/dotnetup" local dotnetup_exe="$dotnetup_dir/dotnetup" - # Re-download dotnetup at most once every 24 hours to avoid unnecessary network calls. - local skip_download=false - if [[ -f "$dotnetup_exe" ]]; then - local current_time - current_time=$(date +%s) - local file_time - file_time=$(stat -c %Y "$dotnetup_exe" 2>/dev/null || stat -f %m "$dotnetup_exe" 2>/dev/null || echo 0) - local age_seconds=$((current_time - file_time)) - if [[ $age_seconds -lt 86400 ]]; then - echo "dotnetup binary is less than 24 hours old; skipping re-download." - skip_download=true - fi - fi - - if [[ "$skip_download" == true && -f "$dotnetup_exe" ]]; then - # dotnetup installs runtimes for its own process architecture, so a cached - # binary of the wrong architecture (e.g. an x64 dotnetup left on a reused - # arm64 agent, or one downloaded under Rosetta 2) would install the wrong - # runtimes. Verify the cached binary's actual architecture against the native - # architecture and re-download on mismatch rather than trusting uname. - local native_arch - native_arch="$(GetNativeMachineArchitecture)" - local cached_arch="" - if [[ "$(uname)" == "Darwin" ]]; then - if file "$dotnetup_exe" 2>/dev/null | grep -q 'arm64'; then - cached_arch="arm64" - elif file "$dotnetup_exe" 2>/dev/null | grep -q 'x86_64'; then - cached_arch="x64" - fi - fi - if [[ -n "$cached_arch" && "$cached_arch" != "$native_arch" ]]; then - echo "Cached dotnetup architecture ($cached_arch) does not match native architecture ($native_arch); re-downloading." - skip_download=false - fi - fi - - if [[ "$skip_download" != true ]]; then - # Acquire the latest dotnetup daily build using the in-repo install script. - # build.sh runs under `set -e`; guard so we can emit a diagnostic. - if ! "$repo_root/scripts/get-dotnetup.sh" --install-dir "$dotnetup_dir"; then + if ! ShouldUseCachedDotnetup "$dotnetup_exe"; then + if ! AcquireDotnetup "$dotnetup_dir"; then Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to acquire dotnetup; falling back to dotnet install script." InstallDotNetSharedFrameworksWithInstallScript "$dotnet_root" "$arch" "${specs_to_install[@]}" return diff --git a/eng/sdk-tools.ps1 b/eng/sdk-tools.ps1 new file mode 100644 index 000000000000..afa988bf8c86 --- /dev/null +++ b/eng/sdk-tools.ps1 @@ -0,0 +1,42 @@ +# General-purpose shared helpers for the SDK repo's build/test scripts. +# Dot-source this file to reuse the functions below; it defines functions only +# and has no top-level side effects, so it is safe to dot-source multiple times. +# +# This is the repo-owned counterpart to arcade's eng/common/tools.ps1: put shared +# logic that is NOT specific to a single feature here. (eng/common is managed by +# arcade and changes there are overwritten, so it cannot host repo-owned helpers.) + +# Maps a System.Runtime.InteropServices.Architecture enum value to the lowercase +# dotnet RID architecture token (e.g. "x64", "arm64"). Unknown values map to "x64". +function ConvertTo-RidArchitecture([System.Runtime.InteropServices.Architecture]$Architecture) { + switch ($Architecture) { + ([System.Runtime.InteropServices.Architecture]::Arm64) { return "arm64" } + ([System.Runtime.InteropServices.Architecture]::X86) { return "x86" } + ([System.Runtime.InteropServices.Architecture]::Arm) { return "arm" } + default { return "x64" } + } +} + +# Detect native OS architecture, which may differ from the process architecture +# (e.g., x64 process running on ARM64 Windows via emulation). +function Get-NativeMachineArchitecture { + try { + return ConvertTo-RidArchitecture ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture) + } + catch { + # Fallback for environments where RuntimeInformation is unavailable + return "x64" + } +} + +# Detect the current process architecture, which may differ from the native OS +# architecture when running under emulation (e.g., an x64 process on ARM64). +function Get-ProcessMachineArchitecture { + try { + return ConvertTo-RidArchitecture ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture) + } + catch { + # Fallback for environments where RuntimeInformation is unavailable + return "x64" + } +} diff --git a/eng/sdk-tools.sh b/eng/sdk-tools.sh new file mode 100644 index 000000000000..190fa20704b0 --- /dev/null +++ b/eng/sdk-tools.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# General-purpose shared helpers for the SDK repo's build/test scripts. +# Dot-source this file to reuse the functions below; it defines functions only +# and has no top-level side effects, so it is safe to source multiple times. +# +# This is the repo-owned counterpart to arcade's eng/common/tools.sh: put shared +# logic that is NOT specific to a single feature here. (eng/common is managed by +# arcade and changes there are overwritten, so it cannot host repo-owned helpers.) + +# Detect native machine architecture, handling macOS Rosetta 2 +# where uname -m may report x86_64 on arm64 hardware. +function GetNativeMachineArchitecture { + if [[ "$(uname)" == "Darwin" ]] && [[ "$(sysctl -n hw.optional.arm64 2>/dev/null)" == "1" ]]; then + echo "arm64" + return + fi + case "$(uname -m)" in + arm64|aarch64) echo "arm64" ;; + amd64|x86_64) echo "x64" ;; + armv*l) echo "arm" ;; + i[3-6]86) echo "x86" ;; + *) echo "x64" ;; + esac +} diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/Commands/Test/TestCommandDefinition.MicrosoftTestingPlatform.cs b/src/Cli/Microsoft.DotNet.Cli.Definitions/Commands/Test/TestCommandDefinition.MicrosoftTestingPlatform.cs index 6987af5d94e4..3e44c84d1a0a 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Definitions/Commands/Test/TestCommandDefinition.MicrosoftTestingPlatform.cs +++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/Commands/Test/TestCommandDefinition.MicrosoftTestingPlatform.cs @@ -88,6 +88,8 @@ public sealed class MicrosoftTestingPlatform : TestCommandDefinition, ICustomHel Description = CommandDefinitionStrings.CmdNoBuildDescription }; + public readonly Option UseCurrentRuntimeOption = CommonOptions.CreateUseCurrentRuntimeOption(CommandDefinitionStrings.CmdCurrentRuntimeOptionDescription); + public readonly Option NoDependenciesOption = new Option("--no-dependencies") { Description = CommandDefinitionStrings.NoDependenciesOptionDescription, @@ -167,6 +169,7 @@ public MicrosoftTestingPlatform() Options.Add(NoBuildOption); Options.Add(NoDependenciesOption); Options.Add(ArtifactsPathOption); + Options.Add(UseCurrentRuntimeOption); Options.Add(NoAnsiOption); Options.Add(NoProgressOption); Options.Add(OutputOption); diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs index 1f94685c28a8..b32e1f6da392 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs @@ -9,23 +9,52 @@ namespace Microsoft.DotNet.Cli.Utils; internal sealed class MSBuildForwardingAppWithoutLogging { + /// + /// An override flag that determines whether to always execute MSBuild out-of-process. By default the managed dotnet CLI + /// prefers to execute MSBuild in-process to prevent needing to spawn another process' central/worker node, + /// but this flag can be used to force out-of-process execution. + /// private static readonly bool AlwaysExecuteMSBuildOutOfProc = Env.GetEnvironmentVariableAsBool("DOTNET_CLI_RUN_MSBUILD_OUTOFPROC"); + + /// + /// An override flag that determines whether to use the MSBuild server - a persistent central node that can serve + /// as a place to cache data and prevent re-doing CoreCLR startup/JITting for small builds. + /// By default, the MSBuild server is disabled due to stability/correctness concerns with some 1P tasks that keep static state around, + /// but it can be used by users that are confident they will not encounter those issues. + /// private static readonly bool UseMSBuildServer = Env.GetEnvironmentVariableAsBool("DOTNET_CLI_USE_MSBUILD_SERVER", false); + + /// + /// What the SDK's opinion is on the default terminal logger. The SDK defaults to 'auto' which will use the terminal logger if the output is going to a terminal, otherwise it will use the console logger. + /// Some users prefer to always use the legacy console logger, so this gives them a way to consistently do so. + /// private static readonly string? TerminalLoggerDefault = Env.GetEnvironmentVariable("DOTNET_CLI_CONFIGURE_MSBUILD_TERMINAL_LOGGER"); public static string MSBuildVersion { get => Build.Evaluation.ProjectCollection.DisplayVersion; } + private const string MSBuildExeName = "MSBuild.dll"; private const string SdksDirectoryName = "Sdks"; + /// + /// The SDK's default MSBuild verbosity level - we choose as a good balance between information and terminal noise. + /// internal const VerbosityOptions DefaultVerbosity = VerbosityOptions.m; - // Null if we're running MSBuild in-proc. + /// + /// The forwarding app implementation for executing MSBuild out-of-process. + /// + /// + /// This is null if we're running MSBuild in-process. + /// private ForwardingAppImplementation? _forwardingApp; + /// + /// A test-only hook for the MSBuildExtensionsPath, which is a key location that MSBuild logic is read from by the MSBuild Common Targets. + /// internal static string? MSBuildExtensionsPathTestHook = null; /// @@ -33,17 +62,25 @@ public static string MSBuildVersion /// private MSBuildArgs _msbuildArgs; - // Path to the MSBuild binary to use. + /// + /// Path to the MSBuild binary to use - this is set by constructor parameter or looked up via . + /// public string MSBuildPath { get; } - // True if, given current state of the class, MSBuild would be executed in its own process. + /// + /// True if, given current state of the class, MSBuild would be executed in its own process. + /// public bool ExecuteMSBuildOutOfProc => _forwardingApp != null; + /// + /// The set of environment variables that must be set on the MSBuild process (or the current + /// process when executing in-proc) for the build to behave correctly. + /// private readonly Dictionary _msbuildRequiredEnvironmentVariables = GetMSBuildRequiredEnvironmentVariables(); private readonly List _msbuildRequiredParameters = ["-maxcpucount", $"--verbosity:{DefaultVerbosity}"]; - public MSBuildForwardingAppWithoutLogging(MSBuildArgs msbuildArgs, string? msbuildPath = null) + public MSBuildForwardingAppWithoutLogging(MSBuildArgs msbuildArgs, string? msbuildPath = null, bool forceOutOfProc = false) { string defaultMSBuildPath = GetMSBuildExePath(); _msbuildArgs = msbuildArgs; @@ -63,8 +100,9 @@ public MSBuildForwardingAppWithoutLogging(MSBuildArgs msbuildArgs, string? msbui EnvironmentVariable("MSBUILDUSESERVER", UseMSBuildServer ? "1" : "0"); - // If DOTNET_CLI_RUN_MSBUILD_OUTOFPROC is set or we're asked to execute a non-default binary, call MSBuild out-of-proc. - if (AlwaysExecuteMSBuildOutOfProc || !string.Equals(MSBuildPath, defaultMSBuildPath, StringComparison.OrdinalIgnoreCase)) + // If DOTNET_CLI_RUN_MSBUILD_OUTOFPROC is set, the caller requires it (e.g. the AOT CLI, which + // cannot host MSBuild in-process), or we're asked to execute a non-default binary, call MSBuild out-of-proc. + if (AlwaysExecuteMSBuildOutOfProc || forceOutOfProc || !string.Equals(MSBuildPath, defaultMSBuildPath, StringComparison.OrdinalIgnoreCase)) { InitializeForOutOfProcForwarding(); } @@ -106,6 +144,9 @@ private static string EmitProperty(KeyValuePair property, string : $"--{label}:{property.Key}={property.Value}"; } + /// + /// Add an environment variable to the state that will be passed to MSBuild when it is run. + /// public void EnvironmentVariable(string name, string? value) { if (_forwardingApp != null) @@ -129,6 +170,9 @@ public void EnvironmentVariable(string name, string? value) } } + /// + /// Run the MSBuild arguments that have been previously specified. + /// public int Execute() { if (_forwardingApp != null) @@ -141,6 +185,11 @@ public int Execute() } } + /// + /// Directly executes MSBuild's method in the current process. + /// Sets up the local environment with required MSBuild environment variables before handing off execution entirely to MSBuild. + /// After execution, the original environment variables are restored for any remaining cleanup work the dotnet CLI needs to perform. + /// public int ExecuteInProc(string[] arguments) { // Save current environment variables before overwriting them. @@ -186,6 +235,10 @@ public int ExecuteInProc(string[] arguments) private static string Escape(string propertyValue) => propertyValue.Replace(";", "%3B").Replace("://", ":%2F%2F"); + /// + /// Gets the path to the MSBuild executable. By default, this will be the 'MSBuild.dll' file in the same location as the `dotnet.dll` binary. + /// + /// private static string GetMSBuildExePath() { return Path.Combine( @@ -193,6 +246,11 @@ private static string GetMSBuildExePath() MSBuildExeName); } + /// + /// Gets the path to the MSBuild SDKs directory - where the SDKs will be loaded from by the default, local-path-based SDK resolver. + /// By default, this will be the 'SDKs' directory in the same location as the `dotnet.dll` binary, but it can be overridden by the `MSBuildSDKsPath` environment variable. + /// + /// public static string GetMSBuildSDKsPath() { var envMSBuildSDKsPath = Environment.GetEnvironmentVariable("MSBuildSDKsPath"); @@ -207,11 +265,17 @@ public static string GetMSBuildSDKsPath() SdksDirectoryName); } - private static string GetDotnetPath() - { - return new Muxer().MuxerPath; - } + private static string GetDotnetPath() => new Muxer().MuxerPath; + /// + /// Gets the required environment variables for MSBuild. + /// The Common Targets require specific environment variables to be set in order to function correctly: + /// + /// MSBuildExtensionsPathThe path to the 'MSBuild extensions' - where the Common Targets themselves will be loaded from. Also where SDK Resolvers will be loaded from. + /// MSBuildSDKsPathThe path to the 'MSBuild SDKs' - where the SDKs will be loaded from by the default resolver. + /// DOTNET_HOST_PATHThe path to the .NET SDK host - used to execute .NET applications by targets in the Common Targets that need to run managed .NET binaries that are not shipped with apphosts. + /// + /// internal static Dictionary GetMSBuildRequiredEnvironmentVariables() { return new() diff --git a/src/Cli/dn/dn-native-debug.vcxproj b/src/Cli/dn/dn-native-debug.vcxproj index ea0f3bc53b95..f827a50fd789 100644 --- a/src/Cli/dn/dn-native-debug.vcxproj +++ b/src/Cli/dn/dn-native-debug.vcxproj @@ -145,7 +145,6 @@ DOTNET_CLI_ENABLEAOT=true - diff --git a/src/Cli/dotnet-aot/AotSourceFiles.props b/src/Cli/dotnet-aot/AotSourceFiles.props index 57cc3069a4f6..68bb6faf525d 100644 --- a/src/Cli/dotnet-aot/AotSourceFiles.props +++ b/src/Cli/dotnet-aot/AotSourceFiles.props @@ -25,12 +25,30 @@ - + + + + + + + + + + + + + + + + + + + @@ -40,9 +58,6 @@ - @@ -56,7 +71,28 @@ + + + + + + + + + + + + + + + + diff --git a/src/Cli/dotnet-aot/DESIGN.md b/src/Cli/dotnet-aot/DESIGN.md index 9e75132c2944..908cf009e995 100644 --- a/src/Cli/dotnet-aot/DESIGN.md +++ b/src/Cli/dotnet-aot/DESIGN.md @@ -94,10 +94,14 @@ A NativeAOT shared library (`NativeLib=Shared`) that exports a single `[UnmanagedCallersOnly]` entry point: `dotnet_execute`. This layer contains the dual-path dispatch logic. -**Fast path** — When `DOTNET_CLI_ENABLEAOT=true`, the AOT bridge compiles a -minimal `Parser` (guarded by `#if CLI_AOT`) that handles simple commands -(`--version`, `--info`) entirely in native code. If the parser recognizes the -command, it executes immediately and returns. +**Fast path** — When `DOTNET_CLI_ENABLEAOT=true`, the AOT bridge builds the +**full** command tree (the same `DotNetCommandDefinition` used by the managed +CLI) so that parsing and `--help` match the managed CLI exactly. Commands that +can run entirely in AOT (`--version`, `--info`, and the AOT-capable `sln` +subcommands) execute immediately and return. Every other command is wired with +a fallback action that throws `CommandNotAvailableInAotException`; the bridge +catches it (and any unexpected parse-time failure) and transparently falls +through to the managed CLI. **Slow path** — When `DOTNET_CLI_ENABLEAOT` is not set or the AOT parser does not handle the command, the bridge calls `ManagedHost.RunApp()`, which uses the @@ -151,20 +155,28 @@ the appropriate implementation: $(DefineConstants);CLI_AOT - + ``` In the shared files: -- **`Parser.cs`** — Under `#if CLI_AOT`, defines a minimal parser with only - `--version` and `--info`. Under `#else`, defines the full command tree. +- **`Parser.cs`** — A single shared `Parser` class builds the same full + `DotNetCommandDefinition` tree in both modes. Only the action wiring differs, + isolated to small inline `#if CLI_AOT` regions: the managed build wires the + real command handlers, while the AOT build attaches a managed-fallback handler + to every command (overriding it with real implementations where AOT can run + the command, e.g. `sln`). The help writer (`DotnetHelpBuilder`) has no + conditional compilation: help for the external-tool commands + (msbuild/nuget/vstest/format/fsi) renders from AOT because those forwarding + apps use AOT-friendly out-of-process codepaths under `#if CLI_AOT`. - **`Program.cs`** — Under `#if CLI_AOT`, provides a simple `Main` that delegates to the AOT parser. Under `#else`, provides the full CLI entry point with telemetry, signal handlers, and workload checks. -- **`CommandLineInfo.cs`** — Uses `#if CLI_AOT` to substitute lightweight - implementations for workload info, localized strings, and OS detection that - would otherwise pull in dependencies incompatible with AOT. +- **`ParserOptionActions.cs`** — The shared `--help`/`--version`/`--info` option + actions. `PrintInfoAction` uses `#if !CLI_AOT` to omit the workload and MSBuild + details that aren't AOT-compatible yet; the diagnostics and `--cli-schema` + actions are `#if !CLI_AOT` (the AOT build defers those to the managed CLI). ```mermaid graph LR diff --git a/src/Cli/dotnet-aot/NativeEntryPoint.cs b/src/Cli/dotnet-aot/NativeEntryPoint.cs index cb6ad6a8722d..542ccb57dd09 100644 --- a/src/Cli/dotnet-aot/NativeEntryPoint.cs +++ b/src/Cli/dotnet-aot/NativeEntryPoint.cs @@ -1,8 +1,12 @@ // 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.Cli.Extensions; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils.Extensions; +using Microsoft.DotNet.Cli.Telemetry; +using System.CommandLine; +using System.Diagnostics; using Microsoft.DotNet.NativeWrapper; namespace Microsoft.DotNet.Cli; @@ -33,6 +37,8 @@ static int Execute( return ExecuteCore(hostPath, dotnetRoot, sdkDir, hostfxrPath, args); } + public static ITelemetryClient? TelemetryClient { get; private set; } + /// /// Core execution logic, separated from native marshalling for testability. /// @@ -40,49 +46,126 @@ internal static int ExecuteCore( string hostPath, string dotnetRoot, string sdkDir, string hostfxrPath, string[] args) { - // Make hostfxr discoverable for NativeWrapper P/Invokes (required on non-Windows) - if (!string.IsNullOrEmpty(hostfxrPath)) + // Telemetry is best-effort and must never prevent the CLI from running. Initializing + // it can fail on some layouts (e.g. the NativeAOT muxer cannot resolve the crypto + // native library used to hash telemetry properties on macOS - see dotnet/sdk#54544), + // so swallow any failure here and continue to the actual command. + Activity? mainActivity = null; + try + { + DateTime preTelemetry = DateTime.UtcNow; + // Initialize OTel telemetry (mirrors managed Program.cs setup). The client is stored in + // the TelemetryClient property so AOT command actions (e.g. --cli-schema) can reuse it. + TelemetryClient = new Telemetry.TelemetryClient(sessionId: null); + DateTime postTelemetry = DateTime.UtcNow; + mainActivity = Activities.Source.StartActivity("native-entrypoint", Telemetry.TelemetryClient.ActivityKind, Telemetry.TelemetryClient.ParentActivityContext); + + // Backdate the activity start to process start time for accurate timing. + if (mainActivity is not null) + { + mainActivity.SetStartTime(Process.GetCurrentProcess().StartTime.ToUniversalTime()); + using var telemetryActivity = Activities.Source.StartActivity("aot-telemetry-setup"); + telemetryActivity?.SetStartTime(preTelemetry); + telemetryActivity?.SetEndTime(postTelemetry); + } + } + catch (Exception ex) { - AppContext.SetData("HOSTFXR_PATH", hostfxrPath); + Debug.WriteLine($"Failed to initialize telemetry in the native entry point: {ex}"); } - // Try the AOT-compiled path for supported commands (if enabled) - if (EnvironmentVariableParser.ParseBool(Environment.GetEnvironmentVariable(EnvironmentVariableNames.DOTNET_CLI_ENABLEAOT), defaultValue: false)) + int exitCode = 1; + bool success = false; + + try { - var parseResult = Parser.Parse(args); - if (parseResult.Errors.Count == 0) + // Make hostfxr discoverable for NativeWrapper P/Invokes (required on non-Windows) + if (!string.IsNullOrEmpty(hostfxrPath)) { - try - { - return Parser.Invoke(parseResult); - } - catch (CommandNotAvailableInAotException) + AppContext.SetData("HOSTFXR_PATH", hostfxrPath); + } + + // Try the AOT-compiled path for supported commands (if enabled) + if (EnvironmentVariableParser.ParseBool(Environment.GetEnvironmentVariable(EnvironmentVariableNames.DOTNET_CLI_ENABLEAOT), defaultValue: false)) + { + ParseResult? parseResult = null; + using (var parse = Activities.Source.StartActivity("aot-parsing")) { - // Command requires managed CLI — fall through to managed fallback below. + try + { + parseResult = Parser.Parse(args); + mainActivity?.SetDisplayName(parseResult); + } + catch (Exception ex) + { + // The full command tree is shared with the managed CLI, so a command-specific parser or + // validator may run during Parse that is only fully supported there. Rather than surface + // an AOT failure, treat any unexpected error while parsing as a signal to fall back to the + // managed CLI, which will re-parse and handle the command (or report the error). This catch + // is intentionally scoped to Parse only — invocation failures must not be masked here, since + // doing so could re-execute a command that already ran (and had side effects) in AOT. + parse?.SetStatus(ActivityStatusCode.Error); + parse?.AddException(ex); + parseResult = null; + } } - catch (Utils.GracefulException ex) + + if (parseResult is not null + && parseResult.Errors.Count == 0 + // An unrecognized top-level token - an external command (`dotnet ef`) or an implicit + // file-based app (`dotnet app.cs`) - is resolved by the managed CLI's external command + // resolution / run pipeline. The shared parser only sees it as the root's hidden + // subcommand argument, so defer to the managed fallback below instead of running the + // root command's usage action. + && !parseResult.RequiresManagedCommandResolution()) { - Reporter.Error.WriteLine(ex.Message.Red()); - return 1; + using var invoke = Activities.Source.StartActivity("aot-invocation"); + try + { + exitCode = Parser.Invoke(parseResult); + success = true; + return exitCode; + } + catch (CommandNotAvailableInAotException) + { + // The parsed command requires the managed CLI — fall through to the managed fallback below. + } + catch (Exception ex) + { + invoke?.SetStatus(ActivityStatusCode.Error); + invoke?.AddException(ex); + exitCode = Parser.ExceptionHandler(ex, parseResult); + success = false; + return exitCode; + } } } - } - // Fall back to the fully managed dotnet CLI by hosting .NET - string dotnetDll = Path.Join(sdkDir, "dotnet.dll"); - string runtimeConfig = Path.Join(sdkDir, "dotnet.runtimeconfig.json"); + // Fall back to the fully managed dotnet CLI by hosting .NET + string dotnetDll = Path.Join(sdkDir, "dotnet.dll"); + string runtimeConfig = Path.Join(sdkDir, "dotnet.runtimeconfig.json"); - if (File.Exists(dotnetDll) && File.Exists(runtimeConfig)) + if (File.Exists(dotnetDll) && File.Exists(runtimeConfig)) + { + // Use the command-line hosting path to run dotnet.dll + string[] appArgs = new string[args.Length + 1]; + appArgs[0] = dotnetDll; + Array.Copy(args, 0, appArgs, 1, args.Length); + exitCode = ManagedHost.RunApp(hostPath, dotnetRoot, hostfxrPath, appArgs); + success = true; + return exitCode; + } + + // No managed fallback available + Console.Error.WriteLine($"The managed fallback could not be located. Expected '{dotnetDll}' and '{runtimeConfig}'."); + return exitCode; + } + finally { - // Use the command-line hosting path to run dotnet.dll - string[] appArgs = new string[args.Length + 1]; - appArgs[0] = dotnetDll; - Array.Copy(args, 0, appArgs, 1, args.Length); - return ManagedHost.RunApp(hostPath, dotnetRoot, hostfxrPath, appArgs); + mainActivity?.AddTag("process.exit.code", exitCode); + mainActivity?.SetStatus(success ? ActivityStatusCode.Ok : ActivityStatusCode.Error); + mainActivity?.Stop(); + Telemetry.TelemetryClient.FlushProviders(); } - - // No managed fallback available - Console.Error.WriteLine($"The managed fallback could not be located. Expected '{dotnetDll}' and '{runtimeConfig}'."); - return 1; } } diff --git a/src/Cli/dotnet/CliSchema.cs b/src/Cli/dotnet/CliSchema.cs index 770f33b65fab..bc2ece066319 100644 --- a/src/Cli/dotnet/CliSchema.cs +++ b/src/Cli/dotnet/CliSchema.cs @@ -91,7 +91,7 @@ public static void PrintCliSchema(ParseResult parseResult, TextWriter outputWrit public static object GetJsonSchema() { - var node = s_jsonContext.Options.GetJsonSchemaAsNode(typeof(RootCommandDetails), new JsonSchemaExporterOptions()); + var node = s_jsonContext.RootCommandDetails.GetJsonSchemaAsNode(new JsonSchemaExporterOptions()); return node.ToJsonString(s_jsonContext.Options); } @@ -199,10 +199,15 @@ private static RootCommandDetails CreateRootCommandDetails(Command command) /// /// Maps some types that don't serialize well to more human-readable strings. /// For example, is serialized as a string instead of an integer. + /// Enums in general are rendered as their name: besides being more readable, this avoids + /// requiring the source-generated to carry metadata + /// for every enum type that might appear as an option/argument default (which is also required + /// for the schema to serialize under NativeAOT). /// private static object? HumanizeValue(object? v) => v switch { VerbosityOptions o => Enum.GetName(o), + Enum e => e.ToString(), null => null, _ => v // For other types, return as is }; diff --git a/src/Cli/dotnet/CommandLineInfo.cs b/src/Cli/dotnet/CommandLineInfo.cs deleted file mode 100644 index b4b99b807711..000000000000 --- a/src/Cli/dotnet/CommandLineInfo.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#nullable disable - -#if !CLI_AOT -using Microsoft.DotNet.Cli.Commands.Workload; -#endif -using Microsoft.DotNet.Cli.Utils; -#if !CLI_AOT -using LocalizableStrings = Microsoft.DotNet.Cli.Utils.LocalizableStrings; -using RuntimeEnvironment = Microsoft.DotNet.Cli.Utils.RuntimeEnvironment; -#endif - -namespace Microsoft.DotNet.Cli; - -public class CommandLineInfo -{ - public static void PrintVersion() - { - Reporter.Output.WriteLine(Product.Version); - } - - public static void PrintInfo() - { - DotnetVersionFile versionFile = DotnetFiles.VersionFileObject; - var commitSha = versionFile.CommitSha ?? "N/A"; -#if CLI_AOT - Reporter.Output.WriteLine(".NET SDK:"); -#else - Reporter.Output.WriteLine($"{LocalizableStrings.DotNetSdkInfoLabel}"); -#endif - Reporter.Output.WriteLine($" Version: {Product.Version}"); - Reporter.Output.WriteLine($" Commit: {commitSha}"); -#if !CLI_AOT - Reporter.Output.WriteLine($" Workload version: {WorkloadInfoHelper.GetWorkloadsVersion()}"); - Reporter.Output.WriteLine($" MSBuild version: {MSBuildForwardingAppWithoutLogging.MSBuildVersion}"); -#endif - Reporter.Output.WriteLine(); -#if CLI_AOT - Reporter.Output.WriteLine("Runtime Environment:"); - Reporter.Output.WriteLine($" OS Name: {System.Runtime.InteropServices.RuntimeInformation.OSDescription}"); - Reporter.Output.WriteLine($" OS Platform: {(OperatingSystem.IsWindows() ? "Windows" : OperatingSystem.IsMacOS() ? "Darwin" : "Linux")}"); -#else - Reporter.Output.WriteLine($"{LocalizableStrings.DotNetRuntimeInfoLabel}"); - Reporter.Output.WriteLine($" OS Name: {RuntimeEnvironment.OperatingSystem}"); - Reporter.Output.WriteLine($" OS Version: {RuntimeEnvironment.OperatingSystemVersion}"); - Reporter.Output.WriteLine($" OS Platform: {RuntimeEnvironment.OperatingSystemPlatform}"); -#endif - Reporter.Output.WriteLine($" RID: {RuntimeInformation.RuntimeIdentifier}"); - Reporter.Output.WriteLine($" Base Path: {AppContext.BaseDirectory}"); -#if !CLI_AOT - PrintWorkloadsInfo(); -#endif - } - -#if !CLI_AOT - private static void PrintWorkloadsInfo() - { - Reporter.Output.WriteLine(); - Reporter.Output.WriteLine($"{LocalizableStrings.DotnetWorkloadInfoLabel}"); - new WorkloadInfoHelper(isInteractive: false).ShowWorkloadsInfo(showVersion: false); - } - - private static string GetDisplayRid(DotnetVersionFile versionFile) - { - FrameworkDependencyFile fxDepsFile = new(); - - string currentRid = RuntimeInformation.RuntimeIdentifier; - - // if the current RID isn't supported by the shared framework, display the RID the CLI was - // built with instead, so the user knows which RID they should put in their "runtimes" section. - return fxDepsFile.IsRuntimeSupported(currentRid) ? - currentRid : - versionFile.BuildRid; - } -#endif -} diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx index 53812c75a31d..7e8e79abb89e 100644 --- a/src/Cli/dotnet/Commands/CliCommandStrings.resx +++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx @@ -205,6 +205,10 @@ Canceling the test session... + + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Workloads managed by Visual Studio must be uninstalled using the Visual Studio Installer. For the version of Visual Studio managing the SDK '{0}', we could not display workloads to uninstall. This is likely because '{0}' uses a different dotnet root path or custom user profile directory from the current running SDK. Paths searched: '{1}', '{2}'. @@ -492,7 +496,7 @@ This is equivalent to deleting project.assets.json. NUMBER - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. Lists packages that have newer versions. Cannot be combined with '--deprecated' or '--vulnerable' options. @@ -2647,6 +2651,10 @@ Proceed? A new handshake '{0}' was received for the test application that doesn't match the previous handshake '{1}'. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + A message of type '{0}' was received in help mode, which is not expected. diff --git a/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs b/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs index 7f8364ddf11c..78f8bbf4581c 100644 --- a/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs +++ b/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs @@ -2,7 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; + +#if !CLI_AOT using System.Reflection; +#endif using Microsoft.DotNet.Cli.Commands.Run; using Microsoft.DotNet.Cli.Telemetry; using Microsoft.DotNet.Cli.Utils; @@ -10,6 +13,18 @@ namespace Microsoft.DotNet.Cli.Commands.MSBuild; +/// +/// Invokes MSBuild consistently across different environments - either in-process or out-of-process. +/// It also ensures that the SDK modifications to default MSBuild behaviors are applied - for example +/// +/// Consuming MSBuild-engine- and SDK-build-logic-emitted telemetry via the central and per-worker-node +/// LLM environment adjustments +/// +/// +/// +/// In AOT mode all MSBuild invocations happen via out-of-process execution, so this should be used with caution - most AOT commands at time of writing +/// do not use MSBuild, and this is mostly intended to make `--help` output for MSBuild-based commands not require jumping into the managed process space. +/// public class MSBuildForwardingApp : CommandBase { private readonly MSBuildForwardingAppWithoutLogging _forwardingAppWithoutLogging; @@ -23,12 +38,24 @@ private static MSBuildArgs ConcatTelemetryLogger(MSBuildArgs msbuildArgs) { try { +#if !CLI_AOT Type loggerType = typeof(MSBuildLogger); Type forwardingLoggerType = typeof(MSBuildForwardingLogger); - + string loggerTypeFullName = loggerType.FullName!; // not-null because these are part of the same assembly + string forwardingLoggerTypeFullName = forwardingLoggerType.FullName!; // not-null because these are part of the same assembly + // The logger assembly locations come from the dotnet assembly we are currently executing in. #pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file - msbuildArgs.OtherMSBuildArgs.Add($"-distributedlogger:{loggerType.FullName},{loggerType.GetTypeInfo().Assembly.Location}*{forwardingLoggerType.FullName},{forwardingLoggerType.GetTypeInfo().Assembly.Location}"); -#pragma warning restore IL3000 + string loggerTypeLocation = loggerType.GetTypeInfo().Assembly.Location; + string forwardingLoggerTypeLocation = forwardingLoggerType.GetTypeInfo().Assembly.Location; +#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file +#else + string loggerTypeFullName = "Microsoft.DotNet.Cli.Commands.MSBuild.MSBuildLogger"; + string forwardingLoggerTypeFullName = "Microsoft.DotNet.Cli.Commands.MSBuild.MSBuildForwardingLogger"; + string loggerTypeLocation = Path.Combine(AppContext.BaseDirectory, "dotnet.dll"); + string forwardingLoggerTypeLocation = loggerTypeLocation; +#endif + + msbuildArgs.OtherMSBuildArgs.Add($"-distributedlogger:{loggerTypeFullName},{loggerTypeLocation}*{forwardingLoggerTypeFullName},{forwardingLoggerTypeLocation}"); return msbuildArgs; } catch (Exception) @@ -40,20 +67,37 @@ private static MSBuildArgs ConcatTelemetryLogger(MSBuildArgs msbuildArgs) } /// - /// Mostly intended for quick/one-shot usage - most 'core' SDK commands should do more hands-on parsing. + /// Initializes a new instance of the class with a set of raw MSBuild arguments. /// + /// + /// Mostly intended for quick/one-shot usage - most 'core' SDK commands should do more hands-on parsing. + /// public MSBuildForwardingApp(IEnumerable rawMSBuildArgs, string? msbuildPath = null) : this( MSBuildArgs.AnalyzeMSBuildArguments(rawMSBuildArgs.ToArray(), CommonOptions.CreatePropertyOption(), CommonOptions.CreateRestorePropertyOption(), CommonOptions.CreateMSBuildTargetOption(), CommonOptions.CreateVerbosityOption(), CommonOptions.CreateNoLogoOption()), msbuildPath) { } + /// + /// Initializes a new instance of the class with a parsed set of MSBuild arguments. + /// These arguments are usually unique per SDK command that needs to invoke MSBuild, because each command may have its own options that + /// 'forward' as different MSBuild arguments. + /// + /// MSBuild arguments to forward to the builder process, parsed by using to apply a set of per-command s to a list of unparsed command line input tokens. + /// The path to the MSBuild executable. If null, the default MSBuild executable will be used. public MSBuildForwardingApp(MSBuildArgs msBuildArgs, string? msbuildPath = null) { var modifiedMSBuildArgs = CommonRunHelpers.AdjustMSBuildForLLMs(ConcatTelemetryLogger(msBuildArgs)); +#if CLI_AOT + const bool forceOutOfProc = true; +#else + const bool forceOutOfProc = false; +#endif _forwardingAppWithoutLogging = new MSBuildForwardingAppWithoutLogging( modifiedMSBuildArgs, - msbuildPath: msbuildPath); + msbuildPath: msbuildPath, + forceOutOfProc: forceOutOfProc); + InitializeRequiredEnvironmentVariables(); } public IEnumerable MSBuildArguments { get { return _forwardingAppWithoutLogging.GetAllArguments(); } } @@ -63,12 +107,7 @@ public void EnvironmentVariable(string name, string? value) _forwardingAppWithoutLogging.EnvironmentVariable(name, value); } - public ProcessStartInfo GetProcessStartInfo() - { - InitializeRequiredEnvironmentVariables(); - - return _forwardingAppWithoutLogging.GetProcessStartInfo(); - } + public ProcessStartInfo GetProcessStartInfo() => _forwardingAppWithoutLogging.GetProcessStartInfo(); private void InitializeRequiredEnvironmentVariables() { @@ -87,20 +126,6 @@ public override int Execute() // Ignore Ctrl-C for the remainder of the command's execution // Forwarding commands will just spawn the child process and exit Console.CancelKeyPress += (sender, e) => { e.Cancel = true; }; - - int exitCode; - if (_forwardingAppWithoutLogging.ExecuteMSBuildOutOfProc) - { - ProcessStartInfo startInfo = GetProcessStartInfo(); - exitCode = startInfo.Execute(); - } - else - { - InitializeRequiredEnvironmentVariables(); - string[] arguments = _forwardingAppWithoutLogging.GetAllArguments(); - exitCode = _forwardingAppWithoutLogging.ExecuteInProc(arguments); - } - - return exitCode; + return _forwardingAppWithoutLogging.Execute(); } } diff --git a/src/Cli/dotnet/Commands/NuGet/NuGetCommand.cs b/src/Cli/dotnet/Commands/NuGet/NuGetCommand.cs index 296e57ede7db..747a00f1d1c4 100644 --- a/src/Cli/dotnet/Commands/NuGet/NuGetCommand.cs +++ b/src/Cli/dotnet/Commands/NuGet/NuGetCommand.cs @@ -14,15 +14,24 @@ internal class NuGetCommand { public static int Run(string[] args, bool isFileBasedApp = false) { +#if CLI_AOT + // The in-process NuGet runner relies on NuGet.CommandLine.XPlat, which isn't AOT-compatible, + // so AOT always forwards to the out-of-process NuGet CLI. + return Run(args, new NuGetCommandRunner()); +#else return Run(args, isFileBasedApp ? new InProcessNuGetCommandRunner(NuGetVirtualProjectBuilder.Instance) : new NuGetCommandRunner()); +#endif } public static int Run(ParseResult parseResult) { ICommandRunner runner; +#if CLI_AOT + runner = new NuGetCommandRunner(); +#else if (parseResult.CommandResult.Command.Name == "why" && parseResult.CommandResult.Command.Arguments.FirstOrDefault() is Argument pathArg && parseResult.GetValue(pathArg) is { } path @@ -34,6 +43,7 @@ public static int Run(ParseResult parseResult) { runner = new NuGetCommandRunner(); } +#endif return Run(parseResult.GetArguments(), runner); } @@ -65,6 +75,7 @@ public int Run(string[] args) } } +#if !CLI_AOT private class InProcessNuGetCommandRunner(NuGetVirtualProjectBuilder virtualProjectBuilder) : ICommandRunner { public int Run(string[] args) @@ -81,6 +92,7 @@ public int Run(string[] args) } } } +#endif private static string GetDotnetPath() { diff --git a/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs b/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs index 59ad5ce7dbba..b85a3297c9c1 100644 --- a/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs +++ b/src/Cli/dotnet/Commands/Run/CommonRunHelpers.cs @@ -37,11 +37,17 @@ public static MSBuildArgs AdjustMSBuildForLLMs(MSBuildArgs msbuildArgs) } } +#if !CLI_AOT /// /// 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. /// + /// + /// This uses the in-process MSBuild logging APIs (Microsoft.Build.*) and so is excluded + /// from the AOT build, which only ever forwards MSBuild out-of-process. + /// public static Microsoft.Build.Framework.ILogger GetConsoleLogger(MSBuildArgs args) => Microsoft.Build.Logging.TerminalLogger.CreateTerminalOrConsoleLogger([.. AdjustMSBuildForLLMs(args).OtherMSBuildArgs]); +#endif } diff --git a/src/Cli/dotnet/Commands/Test/CliConstants.cs b/src/Cli/dotnet/Commands/Test/CliConstants.cs index 9fb46e3a91ff..69955bc87cb0 100644 --- a/src/Cli/dotnet/Commands/Test/CliConstants.cs +++ b/src/Cli/dotnet/Commands/Test/CliConstants.cs @@ -55,6 +55,27 @@ internal static class HandshakeMessagePropertyNames internal const byte ModulePath = 6; internal const byte ExecutionId = 7; internal const byte InstanceId = 8; + internal const byte IsIDE = 9; + + // Reports which command-line execution mode the test host is running in, + // so the SDK can detect mismatches such as a help/list-tests option leaking + // from RunArguments or launchSettings.json into what the SDK thinks is a + // normal run. Values come from HandshakeMessageExecutionModes. + // Optional property — older Microsoft.Testing.Platform versions don't send + // it, in which case the SDK falls back to its previous (no-validation) behavior. + internal const byte ExecutionMode = 10; +} + +internal static class HandshakeMessageExecutionModes +{ + // Standard test run. + internal const string Run = "run"; + + // The test host is going to print command-line help (e.g. --help, -?). + internal const string Help = "help"; + + // The test host is going to discover tests (e.g. --list-tests). + internal const string Discover = "discover"; } internal static class ProtocolConstants diff --git a/src/Cli/dotnet/Commands/Test/MTP/CtrlCCancellationManager.cs b/src/Cli/dotnet/Commands/Test/MTP/CtrlCCancellationManager.cs new file mode 100644 index 000000000000..c2d10c0ed96e --- /dev/null +++ b/src/Cli/dotnet/Commands/Test/MTP/CtrlCCancellationManager.cs @@ -0,0 +1,175 @@ +// 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.Concurrent; +using System.Diagnostics; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Cli.Commands.Test; + +/// +/// Mirrors the two-stage Ctrl+C cancellation UX implemented in Microsoft.Testing.Platform +/// (testfx PR #8581 / SDK issue https://github.com/dotnet/sdk/issues/50732) at the +/// dotnet test orchestrator level: +/// +/// First Ctrl+C: cooperative cancellation. The is signaled so the +/// queue stops scheduling new test apps; running test apps are left alone so they can +/// gracefully report their final state via IPC (their own testfx-side Ctrl+C handler will +/// cancel the session inside the child process). +/// Second Ctrl+C: force exit. Every registered child process is killed +/// (entireProcessTree: true) and the host process exits with +/// (=3). +/// Any further presses are no-ops (the state machine is idempotent). +/// +/// +internal sealed class CtrlCCancellationManager : IDisposable +{ + private const int StateIdle = 0; + private const int StateCancelling = 1; + private const int StateForcing = 2; + + private readonly CancellationTokenSource _cancellationTokenSource = new(); + private readonly Action _onFirstCtrlC; + private readonly Action _exitAction; + private readonly ConcurrentDictionary _processes = new(); + private readonly bool _subscribedToConsole; + private int _state = StateIdle; + private int _disposed; + + public CtrlCCancellationManager(Action onFirstCtrlC, Action? exitAction = null, bool subscribeToConsole = true) + { + _onFirstCtrlC = onFirstCtrlC ?? throw new ArgumentNullException(nameof(onFirstCtrlC)); + _exitAction = exitAction ?? Environment.Exit; + + if (subscribeToConsole) + { + Console.CancelKeyPress += OnConsoleCancelKeyPress; + _subscribedToConsole = true; + } + } + + /// + /// A token that is canceled when the user first presses Ctrl+C. Consumers should use it to + /// stop scheduling new work but should not use it to tear down in-flight IPC for already + /// running test apps (their cooperative cancellation is driven by their own Ctrl+C handler). + /// + public CancellationToken Token => _cancellationTokenSource.Token; + + /// + /// Registers a child test-app process so it will be killed if the user requests a force exit + /// (second Ctrl+C). If the manager is already in the forcing state when this is called, the + /// process is killed immediately to avoid orphaning a child that started during the force + /// exit race window. + /// + public void Register(Process process) + { + ArgumentNullException.ThrowIfNull(process); + + _processes.TryAdd(process, 0); + + if (Volatile.Read(ref _state) == StateForcing) + { + TryKill(process); + } + } + + public void Unregister(Process process) + { + ArgumentNullException.ThrowIfNull(process); + + _processes.TryRemove(process, out _); + } + + /// + /// Test-only hook to drive the state machine without depending on a real Console signal. + /// + internal void SimulateCtrlC() => HandleCtrlC(); + + private void OnConsoleCancelKeyPress(object? sender, ConsoleCancelEventArgs e) + { + // Suppress the runtime's default Ctrl+C handling on every press, including the second one, + // so that we (not the runtime) get to decide the exit code and ordering. This must happen + // before any other work in this handler. + e.Cancel = true; + + HandleCtrlC(); + } + + private void HandleCtrlC() + { + // First press: Idle -> Cancelling. Signal the token, invoke the UI callback. + if (Interlocked.CompareExchange(ref _state, StateCancelling, StateIdle) == StateIdle) + { + // CancellationTokenSource.Cancel() can throw an AggregateException if any registered + // callback throws, or an ObjectDisposedException if Dispose races with a Ctrl+C press + // (e.g. user presses Ctrl+C while we're tearing down). Swallow both — we still want the + // state machine to advance and the UI callback to run. + try + { + _cancellationTokenSource.Cancel(); + } + catch (Exception ex) when (ex is AggregateException or ObjectDisposedException) + { + Logger.LogTrace($"Exception during CtrlCCancellationManager cancel:\n{ex}"); + } + + // The UI callback (typically TerminalTestReporter.StartCancelling) must not be able to + // affect cancellation state — wrap it best-effort. + try + { + _onFirstCtrlC(); + } + catch (Exception ex) + { + Logger.LogTrace($"Exception during CtrlCCancellationManager first-press UI callback:\n{ex}"); + } + + return; + } + + // Second press: Cancelling -> Forcing. Kill every registered child and exit. + // We intentionally do not print any additional message here because the user already saw + // the "Press Ctrl+C again to force exit." hint and the exit itself is the confirmation. + if (Interlocked.CompareExchange(ref _state, StateForcing, StateCancelling) == StateCancelling) + { + foreach (var process in _processes.Keys) + { + TryKill(process); + } + + _exitAction(ExitCode.TestSessionAborted); + } + } + + private static void TryKill(Process process) + { + try + { + if (!process.HasExited) + { + process.Kill(entireProcessTree: true); + } + } + catch (Exception ex) + { + // The process may have exited between the HasExited check and Kill, or we may lack + // permissions to read its state. Either way, nothing useful we can do from here. + Logger.LogTrace($"Exception killing child process during force exit:\n{ex}"); + } + } + + public void Dispose() + { + if (Interlocked.Exchange(ref _disposed, 1) != 0) + { + return; + } + + if (_subscribedToConsole) + { + Console.CancelKeyPress -= OnConsoleCancelKeyPress; + } + + _cancellationTokenSource.Dispose(); + } +} diff --git a/src/Cli/dotnet/Commands/Test/MTP/ExitCode.cs b/src/Cli/dotnet/Commands/Test/MTP/ExitCode.cs index 21a28898b202..ae8fac09f709 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/ExitCode.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/ExitCode.cs @@ -11,6 +11,7 @@ internal static class ExitCode // Values here should align with: https://aka.ms/testingplatform/exitcodes. public const int Success = 0; public const int GenericFailure = 1; + public const int TestSessionAborted = 3; public const int ZeroTests = 8; public const int MinimumExpectedTestsPolicyViolation = 9; } diff --git a/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs b/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs index 569d4374d882..67c0fb7c3512 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs @@ -48,10 +48,11 @@ public int Run(ParseResult parseResult, bool isHelp) EnvironmentVariables: parseResult.GetValue(definition.EnvOption) ?? ImmutableDictionary.Empty); var output = InitializeOutput(degreeOfParallelism, parseResult, testOptions); + using var ctrlC = new CtrlCCancellationManager(output.StartCancelling); int? exitCode = null; try { - var actionQueue = new TestApplicationActionQueue(degreeOfParallelism, buildOptions, testOptions, output, OnHelpRequested); + var actionQueue = new TestApplicationActionQueue(degreeOfParallelism, buildOptions, testOptions, output, OnHelpRequested, ctrlC); exitCode = testHandler.RunTestApplications(actionQueue); // If all test apps exited with 0 exit code, but we detected that handshake didn't happen correctly, map that to generic failure. @@ -113,10 +114,9 @@ private static TerminalTestReporter InitializeOutput(int degreeOfParallelism, Pa MinimumExpectedTests = parseResult.GetValue(definition.MinimumExpectedTestsOption), }); - Console.CancelKeyPress += (s, e) => - { - output.StartCancelling(); - }; + // Ctrl+C handling is wired in Run() through CtrlCCancellationManager so that + // a second press can force-kill running test app child processes and exit with + // ExitCode.TestSessionAborted (see issue https://github.com/dotnet/sdk/issues/50732). // This is ugly, and we need to replace it by passing out some info from testing platform to inform us that some process level retry plugin is active. var isRetry = parseResult.GetArguments().Contains("--retry-failed-tests"); diff --git a/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs b/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs index 43a151d77908..60f365f0c0dc 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs @@ -826,14 +826,19 @@ internal void AssemblyRunCompleted(string executionId, }); } - internal void HandshakeFailure(string assemblyPath, string? targetFramework, int exitCode, string outputData, string errorData) + internal void HandshakeFailure(string assemblyPath, string? targetFramework, int exitCode, string outputData, string errorData, bool reportEvenWhenHelp = false) { - if (_isHelp) - { - // Ignore handshake failures for help for now. - // So far, MTP doesn't handshake on help. - // MTP should be updated for that, however, but this workaround will likely need to stay - // here for a bit to keep compatibility with older MTP versions. It doesn't have to stay for too long though. + if (_isHelp && !reportEvenWhenHelp) + { + // Backward-compat workaround: older Microsoft.Testing.Platform versions don't perform + // a handshake on the --help path (the host just prints help and exits). In that case + // OnTestProcessExited routes here with the "process exited without a usable handshake" + // payload, which is expected and should not be reported as a failure. + // + // Newer MTP versions (microsoft/testfx#8794) always handshake — including on --help — + // so this workaround is only needed while older MTP versions are still in use. Explicit + // protocol-level rejections (e.g. ExecutionMode mismatch) pass reportEvenWhenHelp=true + // and are still surfaced. return; } @@ -886,10 +891,55 @@ private static void AppendAssemblySummary(TestProgressState assemblyRun, ITermin terminal.Append(' '); AppendAssemblyResult(terminal, assemblyRun); terminal.Append(' '); + AppendAssemblyTestCounts(terminal, assemblyRun); + terminal.Append(' '); AppendLongDuration(terminal, assemblyRun.Stopwatch.Elapsed); terminal.AppendLine(); } + /// + /// Renders a compact, per-assembly counts block that mirrors the in-progress indicator. + /// Full-ANSI terminals get "[✓P/xF/↓S]" (with optional "/rR"); simple terminals + /// (NoAnsi / SimpleAnsi / CI) get the ASCII "[+P/xF/?S]" form so logs stay font- and + /// encoding-friendly. Glyphs and colors are intentionally kept in sync with the rendering in + /// and . + /// + private static void AppendAssemblyTestCounts(ITerminal terminal, TestProgressState assemblyRun) + { + int failed = assemblyRun.FailedTests; + int passed = assemblyRun.PassedTests; + int skipped = assemblyRun.SkippedTests; + int retried = assemblyRun.RetriedFailedTests; + + bool unicode = terminal is AnsiTerminal; + char passedGlyph = unicode ? '✓' : '+'; + char skippedGlyph = unicode ? '↓' : '?'; + + terminal.Append('['); + + AppendGlyphCount(terminal, passedGlyph, passed, TerminalColor.DarkGreen); + terminal.Append('/'); + AppendGlyphCount(terminal, 'x', failed, TerminalColor.DarkRed); + terminal.Append('/'); + AppendGlyphCount(terminal, skippedGlyph, skipped, TerminalColor.DarkYellow); + + if (retried > 0) + { + terminal.Append('/'); + AppendGlyphCount(terminal, 'r', retried, TerminalColor.Gray); + } + + terminal.Append(']'); + } + + private static void AppendGlyphCount(ITerminal terminal, char glyph, int count, TerminalColor color) + { + terminal.SetColor(color); + terminal.Append(glyph); + terminal.Append(count.ToString(CultureInfo.CurrentCulture)); + terminal.ResetColor(); + } + /// /// Appends a long duration in human readable format such as 1h 23m 500ms. /// @@ -928,6 +978,7 @@ public void StartCancelling() { terminal.AppendLine(); terminal.AppendLine(CliCommandStrings.CancellingTestSession); + terminal.AppendLine(CliCommandStrings.PressCtrlCAgainToForceExit); terminal.AppendLine(); }); } diff --git a/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs b/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs index c36a00bda8e8..0fa7bbef9454 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs @@ -40,7 +40,7 @@ internal sealed class TestApplication( public bool HasFailureDuringDispose { get; private set; } - public async Task RunAsync() + public async Task RunAsync(CtrlCCancellationManager ctrlC) { if (Interlocked.Exchange(ref _hasRun, 1) != 0) { @@ -53,11 +53,16 @@ public async Task RunAsync() var cancellationToken = cancellationTokenSource.Token; var testAppPipeConnectionLoop = Task.Run(async () => await WaitConnectionAsync(cancellationToken)); + Process? process = null; try { Logger.LogTrace($"Starting test process with command '{processStartInfo.FileName}' and arguments '{processStartInfo.Arguments}'."); - using var process = Process.Start(processStartInfo)!; + process = Process.Start(processStartInfo)!; + + // Register with the Ctrl+C manager so a force-exit (second Ctrl+C) kills this process + // tree even if the child's own cooperative cancellation hangs. + ctrlC.Register(process); // Reading from process stdout/stderr is done on separate threads to avoid blocking IO on the threadpool. // Note: even with 'process.StandardOutput.ReadToEndAsync()' or 'process.BeginOutputReadLine()', we ended up with @@ -119,6 +124,12 @@ public async Task RunAsync() } finally { + if (process is not null) + { + ctrlC.Unregister(process); + process.Dispose(); + } + cancellationTokenSource.Cancel(); await testAppPipeConnectionLoop; } diff --git a/src/Cli/dotnet/Commands/Test/MTP/TestApplicationActionQueue.cs b/src/Cli/dotnet/Commands/Test/MTP/TestApplicationActionQueue.cs index 4c6b8dd316bb..e80d3cb6cfba 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/TestApplicationActionQueue.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/TestApplicationActionQueue.cs @@ -17,14 +17,14 @@ internal class TestApplicationActionQueue private readonly Lock _lock = new(); - public TestApplicationActionQueue(int degreeOfParallelism, BuildOptions buildOptions, TestOptions testOptions, TerminalTestReporter output, Action onHelpRequested) + public TestApplicationActionQueue(int degreeOfParallelism, BuildOptions buildOptions, TestOptions testOptions, TerminalTestReporter output, Action onHelpRequested, CtrlCCancellationManager ctrlC) { _channel = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleReader = false, SingleWriter = false }); _readers = new Task[degreeOfParallelism]; for (int i = 0; i < degreeOfParallelism; i++) { - _readers[i] = Task.Run(async () => await Read(buildOptions, testOptions, output, onHelpRequested)); + _readers[i] = Task.Run(async () => await Read(buildOptions, testOptions, output, onHelpRequested, ctrlC)); } } @@ -48,63 +48,75 @@ public int CompleteEnqueueAndWait() return _aggregateExitCode ?? ExitCode.ZeroTests; } - private async Task Read(BuildOptions buildOptions, TestOptions testOptions, TerminalTestReporter output, Action onHelpRequested) + private async Task Read(BuildOptions buildOptions, TestOptions testOptions, TerminalTestReporter output, Action onHelpRequested, CtrlCCancellationManager ctrlC) { - await foreach (var nonParallelizedGroup in _channel.Reader.ReadAllAsync()) + try { - foreach (var module in nonParallelizedGroup) + await foreach (var nonParallelizedGroup in _channel.Reader.ReadAllAsync(ctrlC.Token)) { - int result = ExitCode.GenericFailure; - var testApp = new TestApplication(module, buildOptions, testOptions, output, onHelpRequested); - try + foreach (var module in nonParallelizedGroup) { - using (testApp) + ctrlC.Token.ThrowIfCancellationRequested(); + + int result = ExitCode.GenericFailure; + var testApp = new TestApplication(module, buildOptions, testOptions, output, onHelpRequested); + try { - result = await testApp.RunAsync(); + using (testApp) + { + result = await testApp.RunAsync(ctrlC); + } + } + catch (Exception ex) + { + var exAsString = ex.ToString(); + Logger.LogTrace($"Exception running test module {module.RunProperties?.Command} {module.RunProperties?.Arguments}: {exAsString}"); + Reporter.Error.WriteLine(string.Format(CliCommandStrings.ErrorRunningTestModule, module.RunProperties?.Command, module.RunProperties?.Arguments, exAsString)); + result = ExitCode.GenericFailure; } - } - catch (Exception ex) - { - var exAsString = ex.ToString(); - Logger.LogTrace($"Exception running test module {module.RunProperties?.Command} {module.RunProperties?.Arguments}: {exAsString}"); - Reporter.Error.WriteLine(string.Format(CliCommandStrings.ErrorRunningTestModule, module.RunProperties?.Command, module.RunProperties?.Arguments, exAsString)); - result = ExitCode.GenericFailure; - } - - if (result == ExitCode.Success && testApp.HasFailureDuringDispose) - { - result = ExitCode.GenericFailure; - } - lock (_lock) - { - if (_aggregateExitCode is null) + if (result == ExitCode.Success && testApp.HasFailureDuringDispose) { - // This is the first result we are getting. - // So we assign the exit code, regardless of whether it's failure or success. - _aggregateExitCode = result; + result = ExitCode.GenericFailure; } - else if (_aggregateExitCode.Value != result) + + lock (_lock) { - if (_aggregateExitCode == ExitCode.Success) + if (_aggregateExitCode is null) { - // The current result we are dealing with is the first failure after previous Success. - // So we assign the current failure. + // This is the first result we are getting. + // So we assign the exit code, regardless of whether it's failure or success. _aggregateExitCode = result; } - else if (result != ExitCode.Success) + else if (_aggregateExitCode.Value != result) { - // If we get a new failure result, which is different from a previous failure, we use GenericFailure. - _aggregateExitCode = ExitCode.GenericFailure; - } - else - { - // The current result is a success, but we already have a failure. - // So, we keep the failure exit code. + if (_aggregateExitCode == ExitCode.Success) + { + // The current result we are dealing with is the first failure after previous Success. + // So we assign the current failure. + _aggregateExitCode = result; + } + else if (result != ExitCode.Success) + { + // If we get a new failure result, which is different from a previous failure, we use GenericFailure. + _aggregateExitCode = ExitCode.GenericFailure; + } + else + { + // The current result is a success, but we already have a failure. + // So, we keep the failure exit code. + } } } } } } + catch (OperationCanceledException) when (ctrlC.Token.IsCancellationRequested) + { + // Stop scheduling new test apps once the user has pressed Ctrl+C the first time. + // Already-running test apps are left alone so they can gracefully cancel themselves + // (and report final session state via IPC); a second Ctrl+C is what force-kills them + // via the CtrlCCancellationManager. + } } } diff --git a/src/Cli/dotnet/Commands/Test/MTP/TestApplicationHandler.cs b/src/Cli/dotnet/Commands/Test/MTP/TestApplicationHandler.cs index fd350d77a710..57a98393e49a 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/TestApplicationHandler.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/TestApplicationHandler.cs @@ -90,16 +90,55 @@ internal bool OnHandshakeReceived(HandshakeMessage handshakeMessage, bool gotSup _output.AssemblyRunStarted(_module.TargetPath, handshakeInfo.TargetFramework, handshakeInfo.Architecture, handshakeInfo.ExecutionId, instanceId!); } + // Validate the optional ExecutionMode property last (after AssemblyRunStarted) so that any + // diagnostic about a mismatched run/help/discover mode is associated with this assembly + // in the terminal output. + // + // Older Microsoft.Testing.Platform versions don't send the ExecutionMode property at all + // (see https://github.com/microsoft/testfx/pull/8794). In that case we keep today's + // behavior and don't perform any validation here. If the property is present, validate it + // even when it is empty/whitespace so protocol bugs are surfaced instead of silently accepted. + if (handshakeMessage.Properties.TryGetValue(HandshakeMessagePropertyNames.ExecutionMode, out string? executionMode) && + !IsExpectedExecutionMode(executionMode, out string expectedExecutionMode)) + { + ReportHandshakeFailure(string.Format(CliCommandStrings.MismatchingHandshakeExecutionMode, executionMode, expectedExecutionMode)); + return false; + } + return true; } + private bool IsExpectedExecutionMode(string reportedMode, out string expectedMode) + { + expectedMode = _options.IsHelp + ? HandshakeMessageExecutionModes.Help + : _options.IsDiscovery + ? HandshakeMessageExecutionModes.Discover + : HandshakeMessageExecutionModes.Run; + + // If the reported mode is one of the known values, it must equal the SDK's expected mode. + // An unknown value (e.g. a future mode added by a newer testing platform without bumping + // the protocol version) is also rejected so we don't silently accept a message stream we + // can't interpret. + return reportedMode == expectedMode; + } + + // Every caller of this helper has just decided to reject the handshake at the protocol level + // (the caller immediately returns false from OnHandshakeReceived). We always opt out of the + // legacy "swallow handshake failures when SDK is in help mode" workaround in + // TerminalTestReporter.HandshakeFailure — that workaround is meant for older Microsoft.Testing.Platform + // versions that don't handshake at all on --help and so OnTestProcessExited ends up calling + // HandshakeFailure with no actionable context. Explicit programmatic rejections here (unsupported + // protocol version, missing required property, mismatching handshake info, mismatching execution + // mode) are real protocol failures and must still be surfaced even when the SDK is in help mode. private void ReportHandshakeFailure(string failureMessage) => _output.HandshakeFailure( _module.TargetPath, string.Empty, ExitCode.GenericFailure, failureMessage, - string.Empty); + string.Empty, + reportEvenWhenHelp: true); private static bool TryGetRequiredHandshakeProperty(HandshakeMessage handshakeMessage, byte propertyId, out string? value, out string? failureMessage) { @@ -141,6 +180,8 @@ private static string GetHandshakePropertyName(byte propertyId) => HandshakeMessagePropertyNames.ModulePath => nameof(HandshakeMessagePropertyNames.ModulePath), HandshakeMessagePropertyNames.ExecutionId => nameof(HandshakeMessagePropertyNames.ExecutionId), HandshakeMessagePropertyNames.InstanceId => nameof(HandshakeMessagePropertyNames.InstanceId), + HandshakeMessagePropertyNames.IsIDE => nameof(HandshakeMessagePropertyNames.IsIDE), + HandshakeMessagePropertyNames.ExecutionMode => nameof(HandshakeMessagePropertyNames.ExecutionMode), _ => string.Empty, }; diff --git a/src/Cli/dotnet/Commands/Test/MTP/ValidationUtility.cs b/src/Cli/dotnet/Commands/Test/MTP/ValidationUtility.cs index 667ada78d1b0..f63d77d2697e 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/ValidationUtility.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/ValidationUtility.cs @@ -45,7 +45,8 @@ static void ValidateOptionsIrrelevantToModulesFilter(ParseResult parseResult, st parseResult.HasOption(definition.ConfigurationOption) || parseResult.HasOption(definition.FrameworkOption) || parseResult.HasOption(definition.TargetPlatformOptions.OperatingSystemOption) || - parseResult.HasOption(definition.TargetPlatformOptions.RuntimeOption)) + parseResult.HasOption(definition.TargetPlatformOptions.RuntimeOption) || + parseResult.HasOption(definition.UseCurrentRuntimeOption)) { throw new GracefulException(CliCommandStrings.CmdOptionCannotBeUsedWithTestModulesDescription); } diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index f629dac3d357..567559c2062a 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. Nezobrazovat úvodní nápis ani zprávu o autorských právech @@ -689,8 +694,8 @@ Jedná se o ekvivalent odstranění project.assets.json. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - Architekturu parametrů, konfiguraci, architekturu, operační systém a modul runtime nejde použít s parametrem --test-modules. + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + Architekturu parametrů, konfiguraci, architekturu, operační systém a modul runtime nejde použít s parametrem --test-modules. @@ -2240,6 +2245,11 @@ Nástroj {1} (verze {2}) se úspěšně nainstaloval. Do souboru manifestu {3} s Možnosti --prerelease a --version v jednom příkazu se nepodporují. + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. Vytiskne pouze seznam odkazů, které se mají stáhnout, aniž by se tento seznam stahoval. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index a7029460e705..e72d88e98092 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. Zeigt kein Startbanner und keine Copyrightmeldung an. @@ -689,8 +694,8 @@ Dies entspricht dem Löschen von "project.assets.json". - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - Die Optionen "Architektur", "Konfiguration", "Framework", "Betriebssystem" und "Runtime" können nicht mit der Option "--test-modules" verwendet werden. + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + Die Optionen "Architektur", "Konfiguration", "Framework", "Betriebssystem" und "Runtime" können nicht mit der Option "--test-modules" verwendet werden. @@ -2240,6 +2245,11 @@ Das Tool "{1}" (Version {2}) wurde erfolgreich installiert. Der Eintrag wird der Die Optionen „--prerelease“ und „--version“ werden im gleichen Befehl nicht unterstützt. + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. Drucken Sie nur die Liste der Links zum Herunterladen, ohne sie herunterzuladen. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index 2663be27d352..9731e6c23e36 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. No mostrar la pancarta de inicio ni el mensaje de copyright. @@ -689,8 +694,8 @@ Esta acción es equivalente a eliminar project.assets.json. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - La arquitectura de opciones, la configuración, el marco, el sistema operativo y el tiempo de ejecución no se pueden usar con la opción "--test-modules". + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + La arquitectura de opciones, la configuración, el marco, el sistema operativo y el tiempo de ejecución no se pueden usar con la opción "--test-modules". @@ -2240,6 +2245,11 @@ La herramienta "{1}" (versión "{2}") se instaló correctamente. Se ha agregado No se admiten las opciones --prerelease y --version en el mismo comando. + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. Imprima solo la lista de vínculos para descargar, sin descargarla. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index 83f13c857f5d..64d2c2d64bf4 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. N'affiche pas la bannière de démarrage ni le message de copyright. @@ -689,8 +694,8 @@ Cela équivaut à supprimer project.assets.json. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - L’architecture, la configuration, le framework, le système d’exploitation et le runtime des options ne peuvent pas être utilisés avec l’option « --test-modules ». + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + L’architecture, la configuration, le framework, le système d’exploitation et le runtime des options ne peuvent pas être utilisés avec l’option « --test-modules ». @@ -2240,6 +2245,11 @@ L'outil '{1}' (version '{2}') a été correctement installé. L'entrée est ajou Les options --prerelease et --version ne sont pas prises en charge dans la même commande. + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. Imprimer uniquement la liste des liens à télécharger sans télécharger. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index 681530d6a5bd..8059fdcfa9bd 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. Evita la visualizzazione del messaggio di avvio o di copyright. @@ -689,8 +694,8 @@ Equivale a eliminare project.assets.json. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - Non è possibile usare l'architettura, la configurazione, il framework, il sistema operativo e il runtime delle opzioni con l'opzione '--test-modules'. + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + Non è possibile usare l'architettura, la configurazione, il framework, il sistema operativo e il runtime delle opzioni con l'opzione '--test-modules'. @@ -2240,6 +2245,11 @@ Lo strumento '{1}' versione '{2}' è stato installato. La voce è stata aggiunta Le opzioni --prerelease e --version non sono supportate nello stesso comando + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. Stampa solo l'elenco dei collegamenti da scaricare senza scaricarlo. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index d1bab0e55938..0f4a871d8715 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. 著作権情報を表示しません。 @@ -689,8 +694,8 @@ This is equivalent to deleting project.assets.json. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - オプションのアーキテクチャ、構成、フレームワーク、オペレーティング システム、ランタイムと '--test-modules' オプションは同時に使用できません。 + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + オプションのアーキテクチャ、構成、フレームワーク、オペレーティング システム、ランタイムと '--test-modules' オプションは同時に使用できません。 @@ -2240,6 +2245,11 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man --prerelease および --version オプションは同じコマンド内ではサポートされません + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. ダウンロードするリンクの一覧をダウンロードせず、印刷だけを行います。 diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index 8c4e41079004..0d215873d8db 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. 시작 배너 또는 저작권 메시지를 표시하지 않습니다. @@ -689,8 +694,8 @@ project.assets.json을 삭제하는 것과 동일합니다. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - 옵션 아키텍처, 구성, 프레임워크, 운영 체제 및 런타임은 '--test-modules' 옵션과 함께 사용할 수 없습니다. + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + 옵션 아키텍처, 구성, 프레임워크, 운영 체제 및 런타임은 '--test-modules' 옵션과 함께 사용할 수 없습니다. @@ -2240,6 +2245,11 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man --prerelease 및 --version 옵션은 같은 명령에서 지원되지 않습니다 + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. 다운로드할 링크 목록을 다운로드하지 않고 인쇄만 합니다. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index d607d7c33732..3386b0e01cb7 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. Nie wyświetlaj baneru początkowego ani komunikatu o prawach autorskich. @@ -689,8 +694,8 @@ Jest to równoważne usunięciu pliku project.assets.json. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - Nie można używać opcji architektury, konfiguracji, struktury, systemu operacyjnego i środowiska uruchomieniowego z opcją „--test-modules”. + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + Nie można używać opcji architektury, konfiguracji, struktury, systemu operacyjnego i środowiska uruchomieniowego z opcją „--test-modules”. @@ -2240,6 +2245,11 @@ Narzędzie „{1}” (wersja „{2}”) zostało pomyślnie zainstalowane. Wpis Opcje --prerelease i --version nie są obsługiwane w tym samym poleceniu + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. Drukuj tylko listę linków do pobrania bez ich pobierania. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index d1bae8e449be..34770f33eca3 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. Não exibe a faixa de inicialização ou a mensagem de direitos autorais. @@ -689,8 +694,8 @@ Isso equivale a excluir o project.assets.json. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - A arquitetura, a configuração, a estrutura, o sistema operacional e o runtime de opções não podem ser usados com a opção "--test-modules". + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + A arquitetura, a configuração, a estrutura, o sistema operacional e o runtime de opções não podem ser usados com a opção "--test-modules". @@ -2240,6 +2245,11 @@ A ferramenta '{1}' (versão '{2}') foi instalada com êxito. A entrada foi adici Não há suporte para as opções --prerelease e --version no mesmo comando. + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. Somente imprimir a lista de links para download sem baixá-la. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index a608916ebe81..8a4bbf644567 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. Не отображать начальный баннер или сообщение об авторских правах. @@ -689,8 +694,8 @@ This is equivalent to deleting project.assets.json. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - Невозможно использовать архитектуру параметров, конфигурацию, платформу, операционную систему и среду выполнения с параметром "--test-modules". + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + Невозможно использовать архитектуру параметров, конфигурацию, платформу, операционную систему и среду выполнения с параметром "--test-modules". @@ -2240,6 +2245,11 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man Параметры --prerelease и --version не поддерживаются в одной и той же команде + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. Печатать только список ссылок для скачивания, не выполняя загрузку. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index a09ece7df0da..35b539ed9a2b 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. Başlangıç bandını veya telif hakkı iletisini görüntüleme. @@ -689,8 +694,8 @@ project.assets.json öğesini silmeyle eşdeğerdir. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - Mimari, yapılandırma, çerçeve, işletim sistemi ve çalışma zamanı seçenekleri '--test-modules' seçeneğiyle kullanılamaz. + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + Mimari, yapılandırma, çerçeve, işletim sistemi ve çalışma zamanı seçenekleri '--test-modules' seçeneğiyle kullanılamaz. @@ -2240,6 +2245,11 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man --prerelease ve --version seçenekleri aynı komutta desteklenmiyor + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. İndirmeden, yalnızca indirilecek bağlantıların listesini yazdırın. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index 65d3e05d1f76..83cf6d9a7a22 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. 不显示启动版权标志或版权消息。 @@ -689,8 +694,8 @@ This is equivalent to deleting project.assets.json. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - 选项体系结构、配置、框架、操作系统和运行时不能与 '--test-modules' 选项一起使用。 + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + 选项体系结构、配置、框架、操作系统和运行时不能与 '--test-modules' 选项一起使用。 @@ -2240,6 +2245,11 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man 不支持在同一命令中同时使用 --prerelease 和 --version 选项 + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. 仅打印要下载的链接的列表,而不下载列表。 diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index cc9ec33f630d..9c12660cd95d 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -132,6 +132,11 @@ Handshake failures: Section header printed at the end of a 'dotnet test' run when one or more test hosts failed to hand-shake with the SDK. Followed by per-assembly exit code, stdout and stderr. + + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + The test host reported execution mode '{0}', but 'dotnet test' expected '{1}'. This typically happens when an option such as '--help', '-?' or '--list-tests' was injected into the test host through a non-CLI channel (e.g. the 'TestingPlatformCommandLineArguments' or 'RunArguments' MSBuild properties, or 'launchSettings.json' commandLineArgs). Pass these options directly to 'dotnet test' instead. + {Locked="dotnet test"}{Locked="--help"}{Locked="-?"}{Locked="--list-tests"}{Locked="TestingPlatformCommandLineArguments"}{Locked="RunArguments"}{Locked="launchSettings.json"}{Locked="commandLineArgs"} + Do not display the startup banner or the copyright message. 不顯示啟始資訊或著作權訊息。 @@ -689,8 +694,8 @@ This is equivalent to deleting project.assets.json. - The options architecture, configuration, framework, operating system, and runtime cannot be used with '--test-modules' option. - 選項結構、設定、架構、作業系統和執行階段不能與 '--test-modules' 選項一起使用。 + The options architecture, configuration, framework, operating system, runtime, and use current runtime cannot be used with '--test-modules' option. + 選項結構、設定、架構、作業系統和執行階段不能與 '--test-modules' 選項一起使用。 @@ -2240,6 +2245,11 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man 同一個命令中不支援 --prerelease 與 --version 選項 + + Press Ctrl+C again to force exit. + Press Ctrl+C again to force exit. + Hint printed under the "Canceling the test session..." banner. Tells the user that pressing Ctrl+C a second time will immediately terminate the dotnet test process and any still-running test app child processes. + Only print the list of links to download without downloading. 只列印要下載的連結清單,而不下載。 diff --git a/src/Cli/dotnet/Extensions/ParseResultExtensions.cs b/src/Cli/dotnet/Extensions/ParseResultExtensions.cs index c60ece1080a4..743c30134dcb 100644 --- a/src/Cli/dotnet/Extensions/ParseResultExtensions.cs +++ b/src/Cli/dotnet/Extensions/ParseResultExtensions.cs @@ -8,14 +8,58 @@ using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils.Extensions; +using Microsoft.DotNet.ProjectTools; using CommandResult = System.CommandLine.Parsing.CommandResult; namespace Microsoft.DotNet.Cli.Extensions; public static class ParseResultExtensions { + public static string RootSubCommandResult(this ParseResult parseResult) => parseResult.RootCommandResult.Children? + .Select(child => parseResult.GetSymbolResultValue(child)) + .FirstOrDefault(subcommand => !string.IsNullOrEmpty(subcommand)) ?? string.Empty; + + public static bool IsTopLevelDotnetCommand(this ParseResult parseResult) => + parseResult.CommandResult.Command.Equals(Parser.RootCommand) && string.IsNullOrEmpty(parseResult.RootSubCommandResult()); + + /// + /// Returns true when the parse result is an unrecognized top-level token that did not match a + /// built-in command and so landed on the root's hidden subcommand argument - e.g. an external + /// command (dotnet ef) or an implicit file-based app (dotnet app.cs). + /// + /// + /// The managed CLI resolves these via external command resolution or its file-based run pipeline + /// (see Program.ExecuteExternalCommand/TryRunFileBasedApp). The NativeAOT entry + /// point cannot do either, so it uses this to defer such invocations to the managed CLI rather + /// than running the root command's usage action. + /// + public static bool RequiresManagedCommandResolution(this ParseResult parseResult) => + parseResult.CommandResult.Command.Equals(Parser.RootCommand) + && !string.IsNullOrEmpty(parseResult.GetValue(Parser.RootCommand.DotnetSubCommand)); + + /// + /// Detects whether this parse result looks like an implicit file-based app invocation + /// (e.g. dotnet app.cs ...), where the only unmatched token is a first argument that + /// resolves to a valid C# entry-point path. Returns the matching token, or . + /// + /// + /// This detection is shared between the managed CLI - which re-dispatches these invocations as + /// dotnet run --file app.cs (see Program.TryRunFileBasedApp) - and the NativeAOT + /// entry point, which cannot run file-based apps itself and so defers them to the managed CLI. + /// + public static Token? GetFileBasedAppEntryPointToken(this ParseResult parseResult) => + parseResult.GetResult(Parser.RootCommand.DotnetSubCommand) is { Tokens: [{ Type: TokenType.Argument, Value: { } } unmatchedCommandOrFile] } + && VirtualProjectBuilder.IsValidEntryPointPath(unmatchedCommandOrFile.Value) + ? unmatchedCommandOrFile + : null; + + private static string? GetSymbolResultValue(this ParseResult parseResult, SymbolResult symbolResult) => symbolResult switch + { + CommandResult commandResult => commandResult.Command.Name, + ArgumentResult argResult => argResult.Tokens.FirstOrDefault()?.Value, + _ => parseResult.GetResult(Parser.RootCommand.DotnetSubCommand)?.GetValueOrDefault() + }; -#if !CLI_AOT /// /// Finds the command of the parse result and invokes help for that command. /// If no command is specified, invokes help for the application. @@ -39,6 +83,31 @@ public static void ShowHelp(this ParseResult parseResult) Parser.Parse([.. filteredTokenValues, "-h"]).Invoke(); } + public static string[] GetArguments(this ParseResult parseResult) => + parseResult.Tokens.Select(t => t.Value).ToArray().GetSubArguments(); + + public static string[] GetSubArguments(this string[] args) + { + var subargs = args.ToList(); + + // Don't remove any arguments that are being passed to the app in dotnet run + var dashDashIndex = subargs.IndexOf("--"); + + var runArgs = dashDashIndex > -1 ? subargs.GetRange(dashDashIndex, subargs.Count() - dashDashIndex) : []; + subargs = dashDashIndex > -1 ? subargs.GetRange(0, dashDashIndex) : subargs; + + // Remove top level command (ex build or publish). + var subargsFiltered = subargs + .SkipWhile(arg => Parser.RootCommand.DiagOption.Name.Equals(arg) + || Parser.RootCommand.DiagOption.Aliases.Contains(arg) + || arg.Equals("dotnet")) + .Skip(1); + + return [.. subargsFiltered, .. runArgs]; + } + +#if !CLI_AOT + public static void ShowHelpOrErrorIfAppropriate(this ParseResult parseResult) { if (parseResult.Errors.Any()) @@ -87,17 +156,10 @@ static bool ErrorContainsAllParts(ReadOnlySpan error, string[] parts) } } - public static string RootSubCommandResult(this ParseResult parseResult) => parseResult.RootCommandResult.Children? - .Select(child => parseResult.GetSymbolResultValue(child)) - .FirstOrDefault(subcommand => !string.IsNullOrEmpty(subcommand)) ?? string.Empty; - public static bool IsDotnetBuiltInCommand(this ParseResult parseResult) => string.IsNullOrEmpty(parseResult.RootSubCommandResult()) || Parser.GetBuiltInCommand(parseResult.RootSubCommandResult()) != null; - public static bool IsTopLevelDotnetCommand(this ParseResult parseResult) => - parseResult.CommandResult.Command.Equals(Parser.RootCommand) && string.IsNullOrEmpty(parseResult.RootSubCommandResult()); - public static bool CanBeInvoked(this ParseResult parseResult) => Parser.GetBuiltInCommand(parseResult.RootSubCommandResult()) != null || parseResult.Tokens.Any(token => token.Type == TokenType.Directive) @@ -110,36 +172,6 @@ public static int HandleMissingCommand(this ParseResult parseResult) return 1; } - public static string[] GetArguments(this ParseResult parseResult) => - parseResult.Tokens.Select(t => t.Value).ToArray().GetSubArguments(); - - public static string[] GetSubArguments(this string[] args) - { - var subargs = args.ToList(); - - // Don't remove any arguments that are being passed to the app in dotnet run - var dashDashIndex = subargs.IndexOf("--"); - - var runArgs = dashDashIndex > -1 ? subargs.GetRange(dashDashIndex, subargs.Count() - dashDashIndex) : []; - subargs = dashDashIndex > -1 ? subargs.GetRange(0, dashDashIndex) : subargs; - - // Remove top level command (ex build or publish). - var subargsFiltered = subargs - .SkipWhile(arg => Parser.RootCommand.DiagOption.Name.Equals(arg) - || Parser.RootCommand.DiagOption.Aliases.Contains(arg) - || arg.Equals("dotnet")) - .Skip(1); - - return [.. subargsFiltered, .. runArgs]; - } - - private static string? GetSymbolResultValue(this ParseResult parseResult, SymbolResult symbolResult) => symbolResult switch - { - CommandResult commandResult => commandResult.Command.Name, - ArgumentResult argResult => argResult.Tokens.FirstOrDefault()?.Value, - _ => parseResult.GetResult(Parser.RootCommand.DotnetSubCommand)?.GetValueOrDefault() - }; - public static IEnumerable? GetRunCommandShorthandProjectValues(this ParseResult parseResult) => parseResult.GetRunPropertyOptions(true)?.Where(property => !property.Contains("=")); diff --git a/src/Cli/dotnet/Installer/Windows/TimestampedFileLogger.cs b/src/Cli/dotnet/Installer/Windows/TimestampedFileLogger.cs index 280184a3bb7e..6008be1db675 100644 --- a/src/Cli/dotnet/Installer/Windows/TimestampedFileLogger.cs +++ b/src/Cli/dotnet/Installer/Windows/TimestampedFileLogger.cs @@ -174,20 +174,20 @@ private void WriteLog(object flushThreshold) /// The message to log. protected override void WriteMessage(string message) { - if (!_messageQueue.IsAddingCompleted) + try { - try + if (!_messageQueue.IsAddingCompleted) { _messageQueue.Add(message); } - catch (ObjectDisposedException) - { - // The logger was disposed between the IsAddingCompleted check and Add. - } - catch (InvalidOperationException) - { - // CompleteAdding was called between the IsAddingCompleted check and Add. - } + } + catch (ObjectDisposedException) + { + // The logger was disposed before or between the IsAddingCompleted check and Add. + } + catch (InvalidOperationException) + { + // CompleteAdding was called between the IsAddingCompleted check and Add. } } } diff --git a/src/Cli/dotnet/NuGetSignatureVerificationEnabler.cs b/src/Cli/dotnet/NuGetSignatureVerificationEnabler.cs index dcf54e505a92..8df5aee7c453 100644 --- a/src/Cli/dotnet/NuGetSignatureVerificationEnabler.cs +++ b/src/Cli/dotnet/NuGetSignatureVerificationEnabler.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if !CLI_AOT using Microsoft.DotNet.Cli.Commands.MSBuild; +#endif using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Cli; @@ -26,6 +28,7 @@ public static void ConditionallyEnable(ForwardingApp forwardingApp, IEnvironment forwardingApp.WithEnvironmentVariable(DotNetNuGetSignatureVerification, value); } +#if !CLI_AOT public static void ConditionallyEnable(MSBuildForwardingApp forwardingApp, IEnvironmentProvider? environmentProvider = null) { ArgumentNullException.ThrowIfNull(forwardingApp, nameof(forwardingApp)); @@ -39,6 +42,7 @@ public static void ConditionallyEnable(MSBuildForwardingApp forwardingApp, IEnvi forwardingApp.EnvironmentVariable(DotNetNuGetSignatureVerification, value); } +#endif private static string GetSignatureVerificationEnablementValue(IEnvironmentProvider? environmentProvider) { diff --git a/src/Cli/dotnet/Parser.cs b/src/Cli/dotnet/Parser.cs index f9a1166919e0..3174169add90 100644 --- a/src/Cli/dotnet/Parser.cs +++ b/src/Cli/dotnet/Parser.cs @@ -1,128 +1,41 @@ -// 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. -#if CLI_AOT using System.CommandLine; +using System.CommandLine.Help; +using System.Reflection; +using Microsoft.DotNet.Cli.Commands; +using Microsoft.DotNet.Cli.Commands.Format; +using Microsoft.DotNet.Cli.Commands.Fsi; +using Microsoft.DotNet.Cli.Commands.Hidden.Add; +using Microsoft.DotNet.Cli.Commands.Hidden.Add.Package; +using Microsoft.DotNet.Cli.Commands.Hidden.List; +using Microsoft.DotNet.Cli.Commands.Hidden.List.Reference; +using Microsoft.DotNet.Cli.Commands.MSBuild; +using Microsoft.DotNet.Cli.Commands.NuGet; using Microsoft.DotNet.Cli.Commands.Solution; +using Microsoft.DotNet.Cli.Commands.Test; +using Microsoft.DotNet.Cli.Commands.VSTest; +using Microsoft.DotNet.Cli.Commands.Workload.Search; +using Microsoft.DotNet.Cli.Extensions; +using Microsoft.DotNet.Cli.Help; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils.Extensions; +using Microsoft.TemplateEngine.Cli; using Command = System.CommandLine.Command; -namespace Microsoft.DotNet.Cli; - -public static class Parser -{ - internal static RootCommand RootCommand { get; } = CreateCommand(); - - private static RootCommand CreateCommand() - { - var versionOption = new Option("--version") { Arity = ArgumentArity.Zero }; - var infoOption = new Option("--info") { Arity = ArgumentArity.Zero }; - - var rootCommand = new RootCommand("dotnet") - { - versionOption, - infoOption, - }; - - rootCommand.SetAction(parseResult => - { - if (parseResult.GetValue(versionOption)) - { - CommandLineInfo.PrintVersion(); - return 0; - } - if (parseResult.GetValue(infoOption)) - { - CommandLineInfo.PrintInfo(); - return 0; - } - parseResult.InvocationConfiguration.Output.WriteLine("Usage: dn [options]"); - return 0; - }); - - ConfigureSolutionCommand(rootCommand); - - return rootCommand; - } - - private static void ConfigureSolutionCommand(RootCommand rootCommand) - { - var slnDef = new SolutionCommandDefinition(); - SolutionCommandParser.ConfigureCommand(slnDef); - rootCommand.Subcommands.Add(slnDef); - } - - public static ParseResult Parse(string[] args) => RootCommand.Parse(args); - - public static int Invoke(ParseResult parseResult) => parseResult.Invoke(InvocationConfiguration); - - /// - /// Implements token-per-line response file handling for the CLI. We use this instead of the built-in S.CL handling - /// to ensure backwards-compatibility with MSBuild. - /// - public static bool TokenPerLine(string tokenToReplace, out IReadOnlyList? replacementTokens, out string? errorMessage) - { - var filePath = Path.GetFullPath(tokenToReplace); - if (File.Exists(filePath)) - { - var lines = File.ReadAllLines(filePath); - var trimmedLines = - lines - // Remove content in the lines that start with # after trimmer leading whitespace - .Select(line => line.TrimStart().StartsWith('#') ? string.Empty : line) - // trim leading/trailing whitespace to not pass along dead spaces - .Select(x => x.Trim()) - // Remove empty lines - .Where(line => line.Length > 0); - replacementTokens = [.. trimmedLines]; - errorMessage = null; - return true; - } - else - { - replacementTokens = null; - errorMessage = string.Format(CliStrings.ResponseFileNotFound, tokenToReplace); - return false; - } - } - - public static ParserConfiguration ParserConfiguration { get; } = new() - { - EnablePosixBundling = false, - ResponseFileTokenReplacer = TokenPerLine - }; - - public static InvocationConfiguration InvocationConfiguration { get; } = new() - { - EnableDefaultExceptionHandler = false, - }; -} - -#else -using System.CommandLine; -using System.CommandLine.Help; +#if !CLI_AOT using System.CommandLine.StaticCompletions; -using System.Reflection; -using Microsoft.DotNet.Cli.Commands; using Microsoft.DotNet.Cli.Commands.Build; using Microsoft.DotNet.Cli.Commands.BuildServer; using Microsoft.DotNet.Cli.Commands.Clean; using Microsoft.DotNet.Cli.Commands.Dnx; -using Microsoft.DotNet.Cli.Commands.Format; -using Microsoft.DotNet.Cli.Commands.Fsi; using Microsoft.DotNet.Cli.Commands.Help; -using Microsoft.DotNet.Cli.Commands.Hidden.Add; -using Microsoft.DotNet.Cli.Commands.Hidden.Add.Package; using Microsoft.DotNet.Cli.Commands.Hidden.Complete; using Microsoft.DotNet.Cli.Commands.Hidden.InternalReportInstallSuccess; -using Microsoft.DotNet.Cli.Commands.Hidden.List; -using Microsoft.DotNet.Cli.Commands.Hidden.List.Reference; using Microsoft.DotNet.Cli.Commands.Hidden.Parse; using Microsoft.DotNet.Cli.Commands.Hidden.Remove; -using Microsoft.DotNet.Cli.Commands.MSBuild; using Microsoft.DotNet.Cli.Commands.New; -using Microsoft.DotNet.Cli.Commands.NuGet; using Microsoft.DotNet.Cli.Commands.Pack; using Microsoft.DotNet.Cli.Commands.Package; using Microsoft.DotNet.Cli.Commands.Project; @@ -132,28 +45,67 @@ public static bool TokenPerLine(string tokenToReplace, out IReadOnlyList using Microsoft.DotNet.Cli.Commands.Run; using Microsoft.DotNet.Cli.Commands.Run.Api; using Microsoft.DotNet.Cli.Commands.Sdk; -using Microsoft.DotNet.Cli.Commands.Solution; -using Microsoft.DotNet.Cli.Commands.Test; using Microsoft.DotNet.Cli.Commands.Tool; using Microsoft.DotNet.Cli.Commands.Tool.Store; -using Microsoft.DotNet.Cli.Commands.VSTest; using Microsoft.DotNet.Cli.Commands.Workload; -using Microsoft.DotNet.Cli.Commands.Workload.Search; -using Microsoft.DotNet.Cli.Extensions; -using Microsoft.DotNet.Cli.Help; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Cli.Utils.Extensions; -using Microsoft.TemplateEngine.Cli; -using Command = System.CommandLine.Command; +#endif namespace Microsoft.DotNet.Cli; public static class Parser { + /// + /// The root command for the .NET CLI. + /// + /// + /// If you use this Command directly, you _must_ use + /// and to ensure that the command line parser + /// and invoker are configured correctly. + /// + internal static DotNetCommandDefinition RootCommand { get; } = CreateCommand(); + private static DotNetCommandDefinition CreateCommand() { + // The full command surface is described by DotNetCommandDefinition, which lives in the + // AOT-compatible Microsoft.DotNet.Cli.Definitions project. Both the managed CLI and the + // AOT bridge build this same tree so that parsing and help match exactly; only the action + // wiring differs between the two (see ConfigureManagedActions / ConfigureAotActions below). var rootCommand = new DotNetCommandDefinition(); + NormalizeRootOptions(rootCommand); + +#if CLI_AOT + ConfigureAotActions(rootCommand); +#else + ConfigureManagedActions(rootCommand); +#endif + + rootCommand.SetAction(parseResult => + { + if (parseResult.GetValue(rootCommand.DiagOption) && parseResult.Tokens.Count == 1) + { + // When user does not specify any args except of diagnostics ("dotnet -d"), + // we do nothing as HandleDiagnosticAction already enabled the diagnostic output. + return 0; + } + else + { + // When user does not specify any args (just "dotnet"), a usage needs to be printed. + parseResult.InvocationConfiguration.Output.WriteLine(CliUsage.HelpText); + return 0; + } + }); + + return rootCommand; + } + + /// + /// Applies tweaks to the options that inherits from + /// : the SDK defines its own --version option, so the built-in + /// one is removed, and the help option is re-pointed at . + /// + private static void NormalizeRootOptions(DotNetCommandDefinition rootCommand) + { for (int i = rootCommand.Options.Count - 1; i >= 0; i--) { Option option = rootCommand.Options[i]; @@ -165,10 +117,14 @@ private static DotNetCommandDefinition CreateCommand() else if (option is HelpOption helpOption) { helpOption.Action = new PrintHelpAction(helpOption, DotnetHelpBuilder.Instance.Value); - option.Description = CliStrings.ShowHelpDescription; + helpOption.Description = CliStrings.ShowHelpDescription; } } + } +#if !CLI_AOT + private static void ConfigureManagedActions(DotNetCommandDefinition rootCommand) + { // Augment the definition of each subcommand with command-specific actions and completions. AddCommandParser.ConfigureCommand(rootCommand.AddCommand); BuildCommandParser.ConfigureCommand(rootCommand.BuildCommand); @@ -222,25 +178,58 @@ private static DotNetCommandDefinition CreateCommand() // https://github.com/NuGet/NuGet.Client/blob/bf048eb714eb6b1912ba868edca4c7cfec454841/src/NuGet.Core/NuGet.CommandLine.XPlat/NuGetCommands.cs // Add `package` subcommands to the definition instead. NuGet.CommandLine.XPlat.NuGetCommands.Add(rootCommand, CommonOptions.CreateInteractiveOption(acceptArgument: true), NuGetVirtualProjectBuilder.Instance); + } +#else + private static void ConfigureAotActions(DotNetCommandDefinition rootCommand) + { + // By default, every command in the AOT build reports that it must run in the managed CLI. + // NativeEntryPoint catches CommandNotAvailableInAotException and falls back to hosting dotnet.dll. + foreach (Command subcommand in rootCommand.Subcommands) + { + SetAotFallbackRecursively(subcommand); + } - rootCommand.SetAction(parseResult => + // Commands that can run entirely in AOT mode wire their real implementations on top of the + // fallback defaults above. SolutionCommandParser is AOT-aware: it keeps real implementations + // for `sln list`/`migrate`/`remove` and falls back for `sln` and `sln add`. + SolutionCommandParser.ConfigureCommand(rootCommand.SolutionCommand); + + rootCommand.VersionOption.Action = new PrintVersionAction(rootCommand.VersionOption); + rootCommand.InfoOption.Action = new PrintInfoAction(rootCommand.InfoOption); + rootCommand.CliSchemaOption.Action = new PrintCliSchemaAction(rootCommand.CliSchemaOption); + + // --list-sdks / --list-runtimes are resolved by the host before the SDK is invoked. If they + // still reach the AOT bridge, defer to the managed CLI rather than printing root usage. + rootCommand.ListSdksOption.Action = new AotFallbackOptionAction(rootCommand.ListSdksOption); + rootCommand.ListRuntimesOption.Action = new AotFallbackOptionAction(rootCommand.ListRuntimesOption); + } + + private static void SetAotFallbackRecursively(Command command) + { + command.SetAction(InvokeAotFallback); + foreach (Command subcommand in command.Subcommands) { - if (parseResult.GetValue(rootCommand.DiagOption) && parseResult.Tokens.Count == 1) - { - // When user does not specify any args except of diagnostics ("dotnet -d"), - // we do nothing as HandleDiagnosticAction already enabled the diagnostic output. - return 0; - } - else + SetAotFallbackRecursively(subcommand); + } + } + + private static int InvokeAotFallback(ParseResult parseResult) => throw new CommandNotAvailableInAotException(); + + private sealed class AotFallbackOptionAction(Option option) : InvocableOptionAction(option) + { + public override bool Terminating => true; + + public override int Invoke(ParseResult parseResult) + { + if (parseResult.GetValue((Option)Option)) { - // When user does not specify any args (just "dotnet"), a usage needs to be printed. - parseResult.InvocationConfiguration.Output.WriteLine(CliUsage.HelpText); - return 0; + throw new CommandNotAvailableInAotException(); } - }); - return rootCommand; + return 0; + } } +#endif public static Command? GetBuiltInCommand(string commandName) => RootCommand.Subcommands.FirstOrDefault(c => c.Name.Equals(commandName, StringComparison.OrdinalIgnoreCase)); @@ -286,16 +275,6 @@ public static bool TokenPerLine(string tokenToReplace, out IReadOnlyList EnableDefaultExceptionHandler = false, }; - /// - /// The root command for the .NET CLI. - /// - /// - /// If you use this Command directly, you _must_ use - /// and to ensure that the command line parser - /// and invoker are configured correctly. - /// - internal static DotNetCommandDefinition RootCommand { get; } = CreateCommand(); - /// /// You probably want to use instead of this method. /// This has to internally split the string into an array of arguments @@ -309,6 +288,11 @@ public static bool TokenPerLine(string tokenToReplace, out IReadOnlyList public static int Invoke(string[] args) => Invoke(Parse(args)); public static Task InvokeAsync(string[] args, CancellationToken cancellationToken = default) => InvokeAsync(Parse(args), cancellationToken); + /// + /// Renders an exception thrown while invoking a command. Shared by the managed CLI + /// (Program.ExecuteInternalCommand) and the AOT bridge (NativeEntryPoint) so both + /// report non-fallback exceptions identically. + /// internal static int ExceptionHandler(Exception? exception, ParseResult parseResult) { if (exception is TargetInvocationException) @@ -392,7 +376,6 @@ public static void additionalOption(HelpContext context) public override void Write(HelpContext context) { var command = context.Command; - var helpArgs = new string[] { "--help" }; // custom help overrides if (command.Equals(RootCommand)) @@ -419,16 +402,16 @@ public override void Write(HelpContext context) } else if (command is VSTestCommandDefinition) { - new VSTestForwardingApp(helpArgs).Execute(); + new VSTestForwardingApp(["--help"]).Execute(); } else if (command is FormatCommandDefinition format) { var arguments = context.ParseResult.GetValue(format.Arguments) ?? []; - new FormatForwardingApp([.. arguments, .. helpArgs]).Execute(); + new FormatForwardingApp([.. arguments, "--help"]).Execute(); } else if (command is FsiCommandDefinition) { - new FsiForwardingApp(helpArgs).Execute(); + new FsiForwardingApp(["--help"]).Execute(); } else if (command is ICustomHelp helpCommand) { @@ -491,4 +474,3 @@ private static bool IsInNuGetCommandTree(Command command) } } } -#endif diff --git a/src/Cli/dotnet/ParserOptionActions.cs b/src/Cli/dotnet/ParserOptionActions.cs index 772ec3fdd8af..0616059bb228 100644 --- a/src/Cli/dotnet/ParserOptionActions.cs +++ b/src/Cli/dotnet/ParserOptionActions.cs @@ -3,12 +3,17 @@ using System.CommandLine; using System.CommandLine.Invocation; +using System.Runtime.InteropServices; +#if !CLI_AOT using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Commands.Workload; +#endif using Microsoft.DotNet.Cli.Extensions; using Microsoft.DotNet.Cli.Help; using Microsoft.DotNet.Cli.Utils; +#if !CLI_AOT using Microsoft.DotNet.Configurer; +#endif using RuntimeEnvironment = Microsoft.DotNet.Cli.Utils.RuntimeEnvironment; namespace Microsoft.DotNet.Cli; @@ -25,6 +30,7 @@ internal abstract class InvocableOptionAction(Option option) : SynchronousComman public Option Option { get; } = option; } +#if !CLI_AOT internal class HandleDiagnosticAction(Option option) : InvocableOptionAction(option) { public override bool Terminating => false; @@ -84,6 +90,7 @@ private bool OptionPrecedesSubcommand(IEnumerable tokens, string subComm return false; } } +#endif internal class PrintHelpAction(Option option, HelpBuilder builder) : InvocableOptionAction(option) { @@ -109,7 +116,9 @@ internal class PrintVersionAction(Option option) : InvocableOptionAction(o public override int Invoke(ParseResult parseResult) { - if (!parseResult.HasOption(Option) || !parseResult.GetValue(option) + // GetResult(Option) is { Implicit: false } is the AOT-friendly equivalent of parseResult.HasOption(Option); + // the HasOption extension lives in Microsoft.DotNet.Cli.CommandLine, which the AOT build doesn't reference. + if (parseResult.GetResult(Option) is not { Implicit: false } || !parseResult.GetValue(option) // Only print for top-level commands. || !parseResult.IsTopLevelDotnetCommand()) { @@ -128,7 +137,7 @@ internal class PrintInfoAction(Option option) : InvocableOptionAction(opti public override int Invoke(ParseResult parseResult) { - if (!parseResult.HasOption(Option) || !parseResult.GetValue(option) + if (parseResult.GetResult(Option) is not { Implicit: false } || !parseResult.GetValue(option) // Only print for top-level commands. || !parseResult.IsTopLevelDotnetCommand()) { @@ -140,22 +149,34 @@ public override int Invoke(ParseResult parseResult) Reporter.Output.WriteLine($"{LocalizableStrings.DotNetSdkInfoLabel}"); Reporter.Output.WriteLine($" Version: {Product.Version}"); Reporter.Output.WriteLine($" Commit: {commitSha}"); +#if !CLI_AOT + // Workload and MSBuild version reporting are not AOT-compatible yet (they pull in the + // workload manager and MSBuild forwarding machinery), so they are omitted from the AOT build. Reporter.Output.WriteLine($" Workload version: {WorkloadInfoHelper.GetWorkloadsVersion()}"); Reporter.Output.WriteLine($" MSBuild version: {MSBuildForwardingAppWithoutLogging.MSBuildVersion}"); +#endif Reporter.Output.WriteLine(); Reporter.Output.WriteLine($"{LocalizableStrings.DotNetRuntimeInfoLabel}"); Reporter.Output.WriteLine($" OS Name: {RuntimeEnvironment.OperatingSystem}"); Reporter.Output.WriteLine($" OS Version: {RuntimeEnvironment.OperatingSystemVersion}"); Reporter.Output.WriteLine($" OS Platform: {RuntimeEnvironment.OperatingSystemPlatform}"); +#if !CLI_AOT Reporter.Output.WriteLine($" RID: {GetDisplayRid(versionFile)}"); +#else + // GetDisplayRid consults the shared framework's deps file, which isn't available in AOT. + Reporter.Output.WriteLine($" RID: {RuntimeInformation.RuntimeIdentifier}"); +#endif Reporter.Output.WriteLine($" Base Path: {AppContext.BaseDirectory}"); +#if !CLI_AOT Reporter.Output.WriteLine(); Reporter.Output.WriteLine($"{LocalizableStrings.DotnetWorkloadInfoLabel}"); new WorkloadInfoHelper(isInteractive: false).ShowWorkloadsInfo(showVersion: false); +#endif return 0; } +#if !CLI_AOT private static string? GetDisplayRid(DotnetVersionFile versionFile) { FrameworkDependencyFile fxDepsFile = new(); @@ -164,6 +185,7 @@ public override int Invoke(ParseResult parseResult) // so the user knows which RID they should put in their "runtimes" section. return fxDepsFile.IsRuntimeSupported(currentRid) ? currentRid : versionFile.BuildRid; } +#endif } internal class PrintCliSchemaAction(Option option) : InvocableOptionAction(option) @@ -172,12 +194,20 @@ internal class PrintCliSchemaAction(Option option) : InvocableOptionAction public override int Invoke(ParseResult parseResult) { - if (!parseResult.HasOption(Option) || !parseResult.GetValue(option)) + if (parseResult.GetResult(Option) is not { Implicit: false } || !parseResult.GetValue(option)) { return 0; } - CliSchema.PrintCliSchema(parseResult, parseResult.InvocationConfiguration.Output, Program.TelemetryInstance); + CliSchema.PrintCliSchema( + parseResult, + parseResult.InvocationConfiguration.Output, +#if CLI_AOT + telemetryClient: NativeEntryPoint.TelemetryClient +#else + telemetryClient: Program.TelemetryInstance +#endif + ); return 0; } diff --git a/src/Cli/dotnet/Program.cs b/src/Cli/dotnet/Program.cs index 37f76e57910b..4ae31bec3b6a 100644 --- a/src/Cli/dotnet/Program.cs +++ b/src/Cli/dotnet/Program.cs @@ -333,8 +333,7 @@ private static int ExecuteExternalCommand(string[] args, ParseResult parseResult { // If we didn't match any built-in commands, and a C# file path is the first argument, // parse as `dotnet run file.cs ..rest_of_args` instead. - if (parseResult.GetResult(Parser.RootCommand.DotnetSubCommand) is { Tokens: [{ Type: TokenType.Argument, Value: { } } unmatchedCommandOrFile] } - && VirtualProjectBuilder.IsValidEntryPointPath(unmatchedCommandOrFile.Value)) + if (parseResult.GetFileBasedAppEntryPointToken() is { } unmatchedCommandOrFile) { List otherTokens = new(parseResult.Tokens.Count - 1); foreach (var token in parseResult.Tokens) diff --git a/src/Cli/dotnet/Telemetry/TelemetryClient.cs b/src/Cli/dotnet/Telemetry/TelemetryClient.cs index 8a6a14c5e2df..c22940996e19 100644 --- a/src/Cli/dotnet/Telemetry/TelemetryClient.cs +++ b/src/Cli/dotnet/Telemetry/TelemetryClient.cs @@ -47,7 +47,7 @@ public class TelemetryClient : ITelemetryClient private static readonly bool s_enableOtlpExporter = Env.GetEnvironmentVariableAsBool(EnvironmentVariableNames.DOTNET_CLI_TELEMETRY_ENABLE_EXPORTER) || (!Env.GetEnvironmentVariableAsBool(EnvironmentVariableNames.OTEL_SDK_DISABLED) && IsOtlpExporterConfiguredByStandardEnvVars()); - private static readonly int s_flushTimeoutMs = 200; + private static readonly int s_flushTimeoutMs = 10; /// /// Returns true if any of the standard OpenTelemetry OTLP exporter environment variables diff --git a/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Task/Microsoft.DotNet.ApiCompat.Task.csproj b/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Task/Microsoft.DotNet.ApiCompat.Task.csproj index fd3d2fedcaae..ad9bf8ec8349 100644 --- a/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Task/Microsoft.DotNet.ApiCompat.Task.csproj +++ b/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Task/Microsoft.DotNet.ApiCompat.Task.csproj @@ -60,9 +60,17 @@ - + + + - diff --git a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI.Task/Microsoft.DotNet.GenAPI.Task.csproj b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI.Task/Microsoft.DotNet.GenAPI.Task.csproj index ce8eb148842e..92ddaf6f3568 100644 --- a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI.Task/Microsoft.DotNet.GenAPI.Task.csproj +++ b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI.Task/Microsoft.DotNet.GenAPI.Task.csproj @@ -38,9 +38,17 @@ - + + + - diff --git a/src/Dotnet.Watch/HotReloadClient/HotReloadClients.cs b/src/Dotnet.Watch/HotReloadClient/HotReloadClients.cs index 62a16616a318..ae65536b3c07 100644 --- a/src/Dotnet.Watch/HotReloadClient/HotReloadClients.cs +++ b/src/Dotnet.Watch/HotReloadClient/HotReloadClients.cs @@ -29,7 +29,7 @@ namespace Microsoft.DotNet.HotReload; /// False to use the to apply static asset updates. /// internal sealed class HotReloadClients( - ImmutableArray<(HotReloadClient client, string name)> clients, + ImmutableArray clients, AbstractBrowserRefreshServer? browserRefreshServer, bool useRefreshServerToApplyStaticAssets) : IDisposable { @@ -38,7 +38,7 @@ internal sealed class HotReloadClients( /// public void Dispose() { - foreach (var (client, _) in clients) + foreach (var client in clients) { client.Dispose(); } @@ -57,6 +57,9 @@ public bool UseRefreshServerToApplyStaticAssets public AbstractBrowserRefreshServer? BrowserRefreshServer => browserRefreshServer; + public ImmutableArray Clients + => clients; + /// /// Invoked when a rude edit is detected at runtime. /// May be invoked multiple times, by each client. @@ -65,14 +68,14 @@ public event Action OnRuntimeRudeEdit { add { - foreach (var (client, _) in clients) + foreach (var client in clients) { client.OnRuntimeRudeEdit += value; } } remove { - foreach (var (client, _) in clients) + foreach (var client in clients) { client.OnRuntimeRudeEdit -= value; } @@ -81,7 +84,7 @@ public event Action OnRuntimeRudeEdit internal void ConfigureLaunchEnvironment(IDictionary environmentBuilder) { - foreach (var (client, _) in clients) + foreach (var client in clients) { client.ConfigureLaunchEnvironment(environmentBuilder); } @@ -92,7 +95,7 @@ internal void ConfigureLaunchEnvironment(IDictionary environment /// Cancellation token. The cancellation should trigger on process terminatation. internal void InitiateConnection(CancellationToken cancellationToken) { - foreach (var (client, _) in clients) + foreach (var client in clients) { client.InitiateConnection(cancellationToken); } @@ -101,7 +104,7 @@ 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))); + await Task.WhenAll(clients.Select(c => c.WaitForConnectionEstablishedAsync(cancellationToken))); } /// Cancellation token. The cancellation should trigger on process terminatation. @@ -113,12 +116,12 @@ public async ValueTask> GetUpdateCapabilitiesAsync(Cancel return []; } - if (clients is [var (singleClient, _)]) + if (clients is [var singleClient]) { return await singleClient.GetUpdateCapabilitiesAsync(cancellationToken); } - var results = await Task.WhenAll(clients.Select(c => c.client.GetUpdateCapabilitiesAsync(cancellationToken))); + var results = await Task.WhenAll(clients.Select(c => c.GetUpdateCapabilitiesAsync(cancellationToken))); // Allow updates that are supported by at least one process. // When applying changes we will filter updates applied to a specific process based on their required capabilities. @@ -137,7 +140,7 @@ public async Task ApplyManagedCodeUpdatesAsync(ImmutableArray c.client.ApplyManagedCodeUpdatesAsync(updates, applyOperationCancellationToken, cancellationToken))); + var applyTasks = await Task.WhenAll(clients.Select(c => c.ApplyManagedCodeUpdatesAsync(updates, applyOperationCancellationToken, cancellationToken))); return CompleteApplyOperationAsync(); @@ -157,13 +160,13 @@ public async ValueTask InitialUpdatesAppliedAsync(CancellationToken cancellation // shouldn't be called if there are no clients Debug.Assert(IsManagedAgentSupported); - if (clients is [var (singleClient, _)]) + if (clients is [var singleClient]) { await singleClient.InitialUpdatesAppliedAsync(cancellationToken); } else { - await Task.WhenAll(clients.Select(c => c.client.InitialUpdatesAppliedAsync(cancellationToken))); + await Task.WhenAll(clients.Select(c => c.InitialUpdatesAppliedAsync(cancellationToken))); } } @@ -189,7 +192,7 @@ public async Task ApplyStaticAssetUpdatesAsync(IEnumerable } catch (Exception e) when (e is not OperationCanceledException) { - clients.First().client.Logger.LogError("Failed to read file {FilePath}: {Message}", asset.FilePath, e.Message); + clients.First().Logger.LogError("Failed to read file {FilePath}: {Message}", asset.FilePath, e.Message); continue; } } @@ -204,7 +207,7 @@ public async ValueTask ApplyStaticAssetUpdatesAsync(ImmutableArray c.client.ApplyStaticAssetUpdatesAsync(updates, applyOperationCancellationToken, cancellationToken))); + var applyTasks = await Task.WhenAll(clients.Select(c => c.ApplyStaticAssetUpdatesAsync(updates, applyOperationCancellationToken, cancellationToken))); return Task.WhenAll(applyTasks); } diff --git a/src/Dotnet.Watch/HotReloadClient/Web/AbstractBrowserRefreshServer.cs b/src/Dotnet.Watch/HotReloadClient/Web/AbstractBrowserRefreshServer.cs index a3dc77fdba9b..d273d0728130 100644 --- a/src/Dotnet.Watch/HotReloadClient/Web/AbstractBrowserRefreshServer.cs +++ b/src/Dotnet.Watch/HotReloadClient/Web/AbstractBrowserRefreshServer.cs @@ -22,12 +22,16 @@ namespace Microsoft.DotNet.HotReload; /// Communicates with aspnetcore-browser-refresh.js loaded in the browser. /// Associated with a project instance. /// -internal abstract class AbstractBrowserRefreshServer(string middlewareAssemblyPath, ILogger logger, ILoggerFactory loggerFactory) : IDisposable +internal abstract class AbstractBrowserRefreshServer( + string middlewareAssemblyPath, + ILogger logger, + Func connectionServerLoggerFactory, + Func connectionAgentLoggerFactory) : IDisposable { - public const string ServerLogComponentName = "BrowserRefreshServer"; - private static readonly JsonSerializerOptions s_jsonSerializerOptions = new(JsonSerializerDefaults.Web); + private static int s_lastConnectionId; + private readonly List _activeConnections = []; private readonly TaskCompletionSource _browserConnected = new(TaskCreationOptions.RunContinuationsAsynchronously); @@ -102,19 +106,39 @@ public void ConfigureLaunchEnvironment(IDictionary builder, bool } } + /// + /// Takes ownership of the . + /// protected BrowserConnection OnBrowserConnected(WebSocket clientSocket, string? subProtocol) { - var sharedSecret = (subProtocol != null) ? _sharedSecretProvider.DecryptSecret(WebUtility.UrlDecode(subProtocol)) : null; + bool connectionPublished = false; + try + { + var sharedSecret = (subProtocol != null) ? _sharedSecretProvider.DecryptSecret(WebUtility.UrlDecode(subProtocol)) : null; - var connection = new BrowserConnection(clientSocket, sharedSecret, loggerFactory); + var connectionId = Interlocked.Increment(ref s_lastConnectionId); + var serverLogger = connectionServerLoggerFactory(connectionId); + var agentLogger = connectionAgentLoggerFactory(connectionId); + var connection = new BrowserConnection(clientSocket, sharedSecret, connectionId, serverLogger, agentLogger); - lock (_activeConnections) + lock (_activeConnections) + { + _activeConnections.Add(connection); + } + + connectionPublished = true; + + serverLogger.Log(LogEvents.ConnectedToRefreshServer); + _browserConnected.TrySetResult(default); + return connection; + } + finally { - _activeConnections.Add(connection); + if (!connectionPublished) + { + clientSocket.Dispose(); + } } - - _browserConnected.TrySetResult(default); - return connection; } /// diff --git a/src/Dotnet.Watch/HotReloadClient/Web/BrowserConnection.cs b/src/Dotnet.Watch/HotReloadClient/Web/BrowserConnection.cs index 101193a7fa39..9ce005c0a679 100644 --- a/src/Dotnet.Watch/HotReloadClient/Web/BrowserConnection.cs +++ b/src/Dotnet.Watch/HotReloadClient/Web/BrowserConnection.cs @@ -12,34 +12,13 @@ namespace Microsoft.DotNet.HotReload; -internal readonly struct BrowserConnection : IDisposable +/// +/// Represents a connection to a browser that facilitates Hot Reload operations. +/// +internal readonly struct BrowserConnection(WebSocket clientSocket, string? sharedSecret, int id, ILogger serverLogger, ILogger agentLogger) : IDisposable { - public const string ServerLogComponentName = $"{nameof(BrowserConnection)}:Server"; - public const string AgentLogComponentName = $"{nameof(BrowserConnection)}:Agent"; - - private static int s_lastId; - - public WebSocket ClientSocket { get; } - public string? SharedSecret { get; } - public int Id { get; } - public ILogger ServerLogger { get; } - public ILogger AgentLogger { get; } - public readonly TaskCompletionSource Disconnected = new(TaskCreationOptions.RunContinuationsAsynchronously); - public BrowserConnection(WebSocket clientSocket, string? sharedSecret, ILoggerFactory loggerFactory) - { - ClientSocket = clientSocket; - SharedSecret = sharedSecret; - Id = Interlocked.Increment(ref s_lastId); - - var displayName = $"Browser #{Id}"; - ServerLogger = loggerFactory.CreateLogger(ServerLogComponentName, displayName); - AgentLogger = loggerFactory.CreateLogger(AgentLogComponentName, displayName); - - ServerLogger.Log(LogEvents.ConnectedToRefreshServer); - } - public void Dispose() { ClientSocket.Dispose(); @@ -48,6 +27,12 @@ public void Dispose() ServerLogger.LogDebug("Disconnected."); } + public WebSocket ClientSocket => clientSocket; + public string? SharedSecret => sharedSecret; + public int Id => id; + public ILogger ServerLogger => serverLogger; + public ILogger AgentLogger => agentLogger; + internal async ValueTask TrySendMessageAsync(ReadOnlyMemory messageBytes, CancellationToken cancellationToken) { #if NET diff --git a/src/Dotnet.Watch/HotReloadClient/Web/BrowserRefreshServer.cs b/src/Dotnet.Watch/HotReloadClient/Web/BrowserRefreshServer.cs index bc5cbc67d007..70f27e678a54 100644 --- a/src/Dotnet.Watch/HotReloadClient/Web/BrowserRefreshServer.cs +++ b/src/Dotnet.Watch/HotReloadClient/Web/BrowserRefreshServer.cs @@ -23,12 +23,13 @@ namespace Microsoft.DotNet.HotReload; /// internal sealed class BrowserRefreshServer( ILogger logger, - ILoggerFactory loggerFactory, + Func connectionServerLoggerFactory, + Func connectionAgentLoggerFactory, string middlewareAssemblyPath, string dotnetPath, WebSocketConfig webSocketConfig, bool suppressTimeouts) - : AbstractBrowserRefreshServer(middlewareAssemblyPath, logger, loggerFactory) + : AbstractBrowserRefreshServer(middlewareAssemblyPath, logger, connectionServerLoggerFactory, connectionAgentLoggerFactory) { protected override bool SuppressTimeouts => suppressTimeouts; @@ -62,6 +63,7 @@ private async Task WebSocketRequestAsync(HttpContext context) var clientSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol); + // client socket ownership is transferred to the connection: var connection = OnBrowserConnected(clientSocket, subProtocol); await connection.Disconnected.Task; } diff --git a/src/Dotnet.Watch/Watch/AppModels/BlazorWebAssemblyAppModel.cs b/src/Dotnet.Watch/Watch/AppModels/BlazorWebAssemblyAppModel.cs index ef0c112b98fb..5b51a5dcd22c 100644 --- a/src/Dotnet.Watch/Watch/AppModels/BlazorWebAssemblyAppModel.cs +++ b/src/Dotnet.Watch/Watch/AppModels/BlazorWebAssemblyAppModel.cs @@ -19,9 +19,9 @@ internal sealed class BlazorWebAssemblyAppModel(DotNetWatchContext context, Proj public override bool ManagedHotReloadRequiresBrowserRefresh => true; - protected override ImmutableArray<(HotReloadClient client, string name)> CreateManagedClients(ILogger clientLogger, ILogger agentLogger, BrowserRefreshServer? browserRefreshServer) + protected override ImmutableArray CreateManagedClients(ILogger clientLogger, ILogger agentLogger, BrowserRefreshServer? browserRefreshServer) { Debug.Assert(browserRefreshServer != null); - return [(CreateWebAssemblyClient(clientLogger, agentLogger, browserRefreshServer, clientProject), "")]; + return [CreateWebAssemblyClient(clientLogger, agentLogger, browserRefreshServer, clientProject)]; } } diff --git a/src/Dotnet.Watch/Watch/AppModels/BlazorWebAssemblyHostedAppModel.cs b/src/Dotnet.Watch/Watch/AppModels/BlazorWebAssemblyHostedAppModel.cs index 768187dbeda3..75769c6a85e2 100644 --- a/src/Dotnet.Watch/Watch/AppModels/BlazorWebAssemblyHostedAppModel.cs +++ b/src/Dotnet.Watch/Watch/AppModels/BlazorWebAssemblyHostedAppModel.cs @@ -21,13 +21,13 @@ internal sealed class BlazorWebAssemblyHostedAppModel(DotNetWatchContext context public override bool ManagedHotReloadRequiresBrowserRefresh => true; - protected override ImmutableArray<(HotReloadClient client, string name)> CreateManagedClients(ILogger clientLogger, ILogger agentLogger, BrowserRefreshServer? browserRefreshServer) + protected override ImmutableArray CreateManagedClients(ILogger clientLogger, ILogger agentLogger, BrowserRefreshServer? browserRefreshServer) { Debug.Assert(browserRefreshServer != null); return [ - (CreateWebAssemblyClient(clientLogger, agentLogger, browserRefreshServer, clientProject), "client"), - (new DefaultHotReloadClient(clientLogger, agentLogger, GetStartupHookPath(serverProject), handlesStaticAssetUpdates: false, new NamedPipeClientTransport(clientLogger)), "host") + CreateWebAssemblyClient(clientLogger, agentLogger, browserRefreshServer, clientProject), + new DefaultHotReloadClient(clientLogger, agentLogger, GetStartupHookPath(serverProject), handlesStaticAssetUpdates: false, new NamedPipeClientTransport(clientLogger)) ]; } } diff --git a/src/Dotnet.Watch/Watch/AppModels/DefaultAppModel.cs b/src/Dotnet.Watch/Watch/AppModels/DefaultAppModel.cs index ac79fc90d8ac..2d8f0f3a7ccf 100644 --- a/src/Dotnet.Watch/Watch/AppModels/DefaultAppModel.cs +++ b/src/Dotnet.Watch/Watch/AppModels/DefaultAppModel.cs @@ -15,7 +15,7 @@ internal sealed class DefaultAppModel(ProjectGraphNode project) : HotReloadAppMo public override ValueTask CreateClientsAsync(ILogger clientLogger, ILogger agentLogger, CancellationToken cancellationToken) => new(new HotReloadClients( clients: IsManagedAgentSupported(project, clientLogger) - ? [(new DefaultHotReloadClient(clientLogger, agentLogger, GetStartupHookPath(project), handlesStaticAssetUpdates: true, new NamedPipeClientTransport(clientLogger)), "")] + ? [new DefaultHotReloadClient(clientLogger, agentLogger, GetStartupHookPath(project), handlesStaticAssetUpdates: true, new NamedPipeClientTransport(clientLogger))] : [], browserRefreshServer: null, useRefreshServerToApplyStaticAssets: false)); diff --git a/src/Dotnet.Watch/Watch/AppModels/MobileAppModel.cs b/src/Dotnet.Watch/Watch/AppModels/MobileAppModel.cs index 198f06f6f20a..3a8381b1c040 100644 --- a/src/Dotnet.Watch/Watch/AppModels/MobileAppModel.cs +++ b/src/Dotnet.Watch/Watch/AppModels/MobileAppModel.cs @@ -16,7 +16,7 @@ internal sealed class MobileAppModel(DotNetWatchContext context, ProjectGraphNod // passed via `dotnet run -e` as @(RuntimeEnvironmentVariable) items. public override async ValueTask CreateClientsAsync(ILogger clientLogger, ILogger agentLogger, CancellationToken cancellationToken) { - ImmutableArray<(HotReloadClient client, string name)> clients; + ImmutableArray clients; if (IsManagedAgentSupported(project, clientLogger)) { var transport = await WebSocketClientTransport.CreateAsync( @@ -24,7 +24,7 @@ public override async ValueTask CreateClientsAsync(ILogger cli clientLogger, cancellationToken); - clients = [(new DefaultHotReloadClient(clientLogger, agentLogger, GetStartupHookPath(project), handlesStaticAssetUpdates: true, transport), "")]; + clients = [new DefaultHotReloadClient(clientLogger, agentLogger, GetStartupHookPath(project), handlesStaticAssetUpdates: true, transport)]; } else { diff --git a/src/Dotnet.Watch/Watch/AppModels/WebApplicationAppModel.cs b/src/Dotnet.Watch/Watch/AppModels/WebApplicationAppModel.cs index a48047c1b91f..4116312c4d87 100644 --- a/src/Dotnet.Watch/Watch/AppModels/WebApplicationAppModel.cs +++ b/src/Dotnet.Watch/Watch/AppModels/WebApplicationAppModel.cs @@ -10,6 +10,10 @@ namespace Microsoft.DotNet.Watch; internal abstract class WebApplicationAppModel(DotNetWatchContext context) : HotReloadAppModel { + public const string ServerLogComponentName = "BrowserRefreshServer"; + public const string ConnectionServerLogComponentName = "BrowserConnection:Server"; + public const string ConnectionAgentLogComponentName = "BrowserConnection:Agent"; + // This needs to be in sync with the version BrowserRefreshMiddleware is compiled against. private static readonly Version s_minimumSupportedVersion = Versions.Version6_0; private const string MiddlewareTargetFramework = "net6.0"; @@ -23,7 +27,7 @@ internal abstract class WebApplicationAppModel(DotNetWatchContext context) : Hot /// public abstract ProjectGraphNode LaunchingProject { get; } - protected abstract ImmutableArray<(HotReloadClient client, string name)> CreateManagedClients(ILogger clientLogger, ILogger agentLogger, BrowserRefreshServer? browserRefreshServer); + protected abstract ImmutableArray CreateManagedClients(ILogger clientLogger, ILogger agentLogger, BrowserRefreshServer? browserRefreshServer); public async sealed override ValueTask CreateClientsAsync(ILogger clientLogger, ILogger agentLogger, CancellationToken cancellationToken) { @@ -49,13 +53,14 @@ private static string GetMiddlewareAssemblyPath() public BrowserRefreshServer? TryCreateRefreshServer(ProjectGraphNode projectNode) { - var logger = context.LoggerFactory.CreateLogger(BrowserRefreshServer.ServerLogComponentName, projectNode.GetDisplayName()); + var logger = context.LoggerFactory.CreateLogger(ServerLogComponentName, projectNode.GetDisplayName()); if (IsServerSupported(projectNode, logger)) { return new BrowserRefreshServer( logger, - context.LoggerFactory, + connectionServerLoggerFactory: connectionId => context.LoggerFactory.CreateLogger(ConnectionServerLogComponentName, GetBrowserLoggerName(connectionId)), + connectionAgentLoggerFactory: connectionId => context.LoggerFactory.CreateLogger(ConnectionAgentLogComponentName, GetBrowserLoggerName(connectionId)), middlewareAssemblyPath: GetMiddlewareAssemblyPath(), dotnetPath: context.EnvironmentOptions.GetMuxerPath(), webSocketConfig: context.EnvironmentOptions.BrowserWebSocketConfig, @@ -65,6 +70,9 @@ private static string GetMiddlewareAssemblyPath() return null; } + private static string GetBrowserLoggerName(int connectionId) + => $"Browser #{connectionId}"; + public bool IsServerSupported(ProjectGraphNode projectNode, ILogger logger) { if (context.EnvironmentOptions.SuppressBrowserRefresh) diff --git a/src/Dotnet.Watch/Watch/AppModels/WebServerAppModel.cs b/src/Dotnet.Watch/Watch/AppModels/WebServerAppModel.cs index 04727dee7984..dd1df815fc5d 100644 --- a/src/Dotnet.Watch/Watch/AppModels/WebServerAppModel.cs +++ b/src/Dotnet.Watch/Watch/AppModels/WebServerAppModel.cs @@ -16,6 +16,6 @@ internal sealed class WebServerAppModel(DotNetWatchContext context, ProjectGraph public override bool ManagedHotReloadRequiresBrowserRefresh => false; - protected override ImmutableArray<(HotReloadClient client, string name)> CreateManagedClients(ILogger clientLogger, ILogger agentLogger, BrowserRefreshServer? browserRefreshServer) - => [(new DefaultHotReloadClient(clientLogger, agentLogger, GetStartupHookPath(serverProject), handlesStaticAssetUpdates: true, new NamedPipeClientTransport(clientLogger)), "")]; + protected override ImmutableArray CreateManagedClients(ILogger clientLogger, ILogger agentLogger, BrowserRefreshServer? browserRefreshServer) + => [new DefaultHotReloadClient(clientLogger, agentLogger, GetStartupHookPath(serverProject), handlesStaticAssetUpdates: true, new NamedPipeClientTransport(clientLogger))]; } diff --git a/src/Dotnet.Watch/Watch/HotReload/HotReloadDotNetWatcher.cs b/src/Dotnet.Watch/Watch/HotReload/HotReloadDotNetWatcher.cs index d2b8bad2d90b..91ae3f2a609e 100644 --- a/src/Dotnet.Watch/Watch/HotReload/HotReloadDotNetWatcher.cs +++ b/src/Dotnet.Watch/Watch/HotReload/HotReloadDotNetWatcher.cs @@ -1073,29 +1073,36 @@ async ValueTask BuildWithFrameworkAndDeviceSelectionAsync() } } - // Select device if needed: - if (needsDeviceSelection - && rootProject.Targets.ContainsKey(TargetNames.ComputeAvailableDevices)) + // Select device if needed. + // Check the TFM-specific inner project node for ComputeAvailableDevices, since workload + // targets (e.g., MAUI) may only be imported when TargetFramework is set. + if (needsDeviceSelection) { Debug.Assert(deviceSelector != null); + Debug.Assert(projectGraph != null); - var deviceInfo = await TrySelectDeviceAsync(projectGraph, rootProject, targetFramework, deviceSelector, cancellationToken); - if (deviceInfo == null) + var projectNodeForDeviceCheck = projectGraph.TryGetProjectNode(rootProject.FullPath, targetFramework); + if (projectNodeForDeviceCheck != null + && projectNodeForDeviceCheck.ProjectInstance.Targets.ContainsKey(TargetNames.ComputeAvailableDevices)) { - return false; - } + var deviceInfo = await TrySelectDeviceAsync(projectGraph, rootProject, targetFramework, deviceSelector, cancellationToken); + if (deviceInfo == null) + { + return false; + } - selectedDevice = deviceInfo.Id; - selectedDeviceRuntimeIdentifier = deviceInfo.RuntimeIdentifier; - _context.Logger.LogDebug("Selected device: {DeviceId}", selectedDevice); + selectedDevice = deviceInfo.Id; + selectedDeviceRuntimeIdentifier = deviceInfo.RuntimeIdentifier; + _context.Logger.LogDebug("Selected device: {DeviceId}", selectedDevice); - // If the device provides a RuntimeIdentifier, re-restore so the assets file - // includes the RID target. This mirrors the dotnet-run behavior. - if (!string.IsNullOrEmpty(selectedDeviceRuntimeIdentifier)) - { - if (!await BuildAsync(BuildAction.RestoreOnly, targetFramework, deviceInfo)) + // If the device provides a RuntimeIdentifier, re-restore so the assets file + // includes the RID target. This mirrors the dotnet-run behavior. + if (!string.IsNullOrEmpty(selectedDeviceRuntimeIdentifier)) { - return false; + if (!await BuildAsync(BuildAction.RestoreOnly, targetFramework, deviceInfo)) + { + return false; + } } } } diff --git a/src/Dotnet.Watch/Watch/UI/IReporter.cs b/src/Dotnet.Watch/Watch/UI/IReporter.cs index 140558c3c867..cf1bdafb13a1 100644 --- a/src/Dotnet.Watch/Watch/UI/IReporter.cs +++ b/src/Dotnet.Watch/Watch/UI/IReporter.cs @@ -175,9 +175,9 @@ public static MessageDescriptor GetDescriptor(EventId id) .Add(DotNetWatchContext.BuildLogComponentName, Emoji.Build) .Add(HotReloadDotNetWatcher.ClientLogComponentName, Emoji.HotReload) .Add(HotReloadDotNetWatcher.AgentLogComponentName, Emoji.Agent) - .Add(BrowserRefreshServer.ServerLogComponentName, Emoji.Refresh) - .Add(BrowserConnection.AgentLogComponentName, Emoji.Agent) - .Add(BrowserConnection.ServerLogComponentName, Emoji.Browser) + .Add(WebApplicationAppModel.ServerLogComponentName, Emoji.Refresh) + .Add(WebApplicationAppModel.ConnectionAgentLogComponentName, Emoji.Agent) + .Add(WebApplicationAppModel.ConnectionServerLogComponentName, Emoji.Browser) .Add(AspireServiceFactory.AspireLogComponentName, Emoji.Aspire); // predefined messages used for testing: @@ -200,7 +200,7 @@ public static MessageDescriptor GetDescriptor(EventId id) public static readonly MessageDescriptor ManagedCodeChangesApplied = Create("C# and Razor changes applied in {0}ms.", Emoji.HotReload, LogLevel.Information); public static readonly MessageDescriptor StaticAssetsChangesApplied = Create("Static asset changes applied in {0}ms.", Emoji.HotReload, LogLevel.Information); public static readonly MessageDescriptor StaticWebAssetManifestNotFound = Create("Static web asset manifest not found.", Emoji.Warning, LogLevel.Warning); - public static readonly MessageDescriptor ScopedCssBundleFileNotFound = Create("Scoped CSS bundle file '{BundleFile}' not found.", Emoji.Warning, LogLevel.Warning); + public static readonly MessageDescriptor ScopedCssBundleFileNotFound = Create("Scoped CSS bundle file '{0}' not found.", Emoji.Warning, LogLevel.Warning); public static readonly MessageDescriptor> ChangesAppliedToProjectsNotification = CreateNotification>(); public static readonly MessageDescriptor SendingUpdateBatch = Create(LogEvents.SendingUpdateBatch, Emoji.HotReload); public static readonly MessageDescriptor UpdateBatchCompleted = Create(LogEvents.UpdateBatchCompleted, Emoji.HotReload); diff --git a/src/Layout/redist/targets/OverlaySdkOnLKG.targets b/src/Layout/redist/targets/OverlaySdkOnLKG.targets index 17054e20e3f4..086df0a04eed 100644 --- a/src/Layout/redist/targets/OverlaySdkOnLKG.targets +++ b/src/Layout/redist/targets/OverlaySdkOnLKG.targets @@ -57,6 +57,20 @@ + + + + <_UserHome Condition="'$(USERPROFILE)' != ''">$(USERPROFILE) + <_UserHome Condition="'$(_UserHome)' == ''">$(HOME) + <_CredentialProviderPath>$(_UserHome)/.nuget/plugins/netcore/CredentialProvider.Microsoft/CredentialProvider.Microsoft.dll + + + <_OverlaySdkEnvVars Include="DOTNET_CLI_HOME=$(ArtifactsTmpDir)" /> + <_OverlaySdkEnvVars Condition="Exists('$(_CredentialProviderPath)')" + Include="NUGET_PLUGIN_PATHS=$(_CredentialProviderPath)" /> + + + + + + + + + diff --git a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.CSharp.NetAnalyzers/Microsoft.NetCore.Analyzers/Usage/CSharpMissingShebangInFileBasedProgram.cs b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.CSharp.NetAnalyzers/Microsoft.NetCore.Analyzers/Usage/CSharpMissingShebangInFileBasedProgram.cs index 35b275ed11c4..3dabf2b97de8 100644 --- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.CSharp.NetAnalyzers/Microsoft.NetCore.Analyzers/Usage/CSharpMissingShebangInFileBasedProgram.cs +++ b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.CSharp.NetAnalyzers/Microsoft.NetCore.Analyzers/Usage/CSharpMissingShebangInFileBasedProgram.cs @@ -27,31 +27,6 @@ public override void Initialize(AnalysisContext context) return; } - // Count non-generated trees upfront so we can report directly - // from a SyntaxTreeAction without needing CompilationEnd. - // We avoid CompilationEnd so diagnostics appear as live IDE diagnostics. - // We replicate Roslyn's generated code detection here because - // Compilation.SyntaxTrees is the raw set (unlike RegisterSyntaxTreeAction - // which gets automatic filtering via ConfigureGeneratedCodeAnalysis). - int nonGeneratedTreeCount = 0; - foreach (var tree in context.Compilation.SyntaxTrees) - { - if (IsGeneratedCode(tree, context.Options.AnalyzerConfigOptionsProvider)) - { - continue; - } - - nonGeneratedTreeCount++; - } - - // Only report when there are multiple non-generated files - // (i.e., #:include directives are used). - // Single-file programs don't need a shebang to distinguish the entry point. - if (nonGeneratedTreeCount <= 1) - { - return; - } - context.RegisterSyntaxTreeAction(context => { if (!context.Tree.FilePath.Equals(entryPointFilePath, StringComparison.Ordinal)) @@ -65,68 +40,37 @@ public override void Initialize(AnalysisContext context) return; } - var location = root.GetFirstToken(includeZeroWidth: true).GetLocation(); + var includeDirective = root.GetLeadingTrivia().FirstOrDefault(IsIncludeDirective); + if (includeDirective == default) + { + return; + } + + var location = includeDirective.GetLocation(); context.ReportDiagnostic(location.CreateDiagnostic(Rule)); }); }); } - /// - /// Replicates Roslyn's generated code detection which checks: - /// the generated_code analyzer config option, - /// common file name patterns, and <auto-generated> comment headers. - /// Based on GeneratedCodeUtilities. - /// - private static bool IsGeneratedCode(SyntaxTree tree, AnalyzerConfigOptionsProvider optionsProvider) + private static bool IsIncludeDirective(SyntaxTrivia trivia) { - if (optionsProvider.GetOptions(tree) - .TryGetValue("generated_code", out var generatedValue) && - generatedValue.Equals("true", StringComparison.OrdinalIgnoreCase)) - { - return true; - } + const string include = "include"; - var filePath = tree.FilePath; - if (!string.IsNullOrEmpty(filePath)) + var structure = trivia.GetStructure(); + if (structure is null) { - var fileName = Path.GetFileName(filePath); - if (fileName.StartsWith("TemporaryGeneratedFile_", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - - var nameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); - if (nameWithoutExtension.EndsWith(".designer", StringComparison.OrdinalIgnoreCase) || - nameWithoutExtension.EndsWith(".generated", StringComparison.OrdinalIgnoreCase) || - nameWithoutExtension.EndsWith(".g", StringComparison.OrdinalIgnoreCase) || - nameWithoutExtension.EndsWith(".g.i", StringComparison.OrdinalIgnoreCase)) - { - return true; - } + return false; } - // Check for or comment at the top of the file. - foreach (var trivia in tree.GetRoot().GetLeadingTrivia()) + var content = structure.ChildTokens().FirstOrDefault(static token => token.IsKind(SyntaxKind.StringLiteralToken)); + if (!content.IsKind(SyntaxKind.StringLiteralToken)) { - switch (trivia.Kind()) - { - case SyntaxKind.SingleLineCommentTrivia: - case SyntaxKind.MultiLineCommentTrivia: - var text = trivia.ToString(); - if (text.Contains(" "hello"; }"""), }, AnalyzerConfigFiles = { ("/.globalconfig", GlobalConfig) }, @@ -32,6 +36,25 @@ public async Task EntryPointWithoutShebang_MultipleFiles_WarningAsync() new DiagnosticResult(MissingShebangInFileBasedProgram.Rule).WithLocation("Test0.cs", 1, 1), }, }, + SolutionTransforms = { EnableFileBasedProgramFeature }, + }.RunAsync(TestContext.Current.CancellationToken); + } + + [Fact] + public async Task ExtraCompileFileNotFromIncludeDirective_NoDiagnosticAsync() + { + // A second Compile item from other MSBuild code does not require a shebang. + await new VerifyCS.Test + { + TestState = + { + Sources = + { + ("Test0.cs", """class Program { static void Main() { } }"""), + ("Util.cs", """class Util { public static string Greet() => "hello"; }"""), + }, + AnalyzerConfigFiles = { ("/.globalconfig", GlobalConfig) }, + }, }.RunAsync(TestContext.Current.CancellationToken); } @@ -74,7 +97,10 @@ public async Task EntryPointWithoutShebang_CodeFixAddsShebangAsync() { Sources = { - ("Test0.cs", """class Program { static void Main() { } }"""), + ("Test0.cs", """ + #:include Util.cs + class Program { static void Main() { } } + """), ("Util.cs", """class Util { public static string Greet() => "hello"; }"""), }, AnalyzerConfigFiles = { ("/.globalconfig", GlobalConfig) }, @@ -89,23 +115,14 @@ public async Task EntryPointWithoutShebang_CodeFixAddsShebangAsync() { ("Test0.cs", """ #!/usr/bin/env dotnet + #:include Util.cs class Program { static void Main() { } } """), ("Util.cs", """class Util { public static string Greet() => "hello"; }"""), }, }, CodeFixTestBehaviors = CodeFixTestBehaviors.SkipLocalDiagnosticCheck, - SolutionTransforms = - { - (solution, projectId) => - { - // Enable #! shebang support in the parser. - var parseOptions = (CSharpParseOptions)solution.GetProject(projectId)!.ParseOptions!; - return solution.WithProjectParseOptions(projectId, - parseOptions.WithFeatures(parseOptions.Features.Concat( - [new KeyValuePair("FileBasedProgram", "true")]))); - }, - }, + SolutionTransforms = { EnableFileBasedProgramFeature }, }.RunAsync(TestContext.Current.CancellationToken); } @@ -121,22 +138,14 @@ public async Task EntryPointWithShebang_MultipleFiles_NoDiagnosticAsync() { ("Test0.cs", """ #!/usr/bin/env dotnet + #:include Util.cs class Program { static void Main() { } } """), ("Util.cs", """class Util { public static string Greet() => "hello"; }"""), }, AnalyzerConfigFiles = { ("/.globalconfig", GlobalConfig) }, }, - SolutionTransforms = - { - (solution, projectId) => - { - var parseOptions = (CSharpParseOptions)solution.GetProject(projectId)!.ParseOptions!; - return solution.WithProjectParseOptions(projectId, - parseOptions.WithFeatures(parseOptions.Features.Concat( - [new KeyValuePair("FileBasedProgram", "true")]))); - }, - }, + SolutionTransforms = { EnableFileBasedProgramFeature }, }.RunAsync(TestContext.Current.CancellationToken); } @@ -161,8 +170,7 @@ public async Task EmptyEntryPointFilePath_NoDiagnosticAsync() [Fact] public async Task GeneratedCodeFile_NoDiagnosticAsync() { - // Entry point file without shebang, but the second file is generated code (.g.cs), - // so there is effectively only one non-generated file - no diagnostic. + // Entry point file without shebang, but no #:include directive - no diagnostic. await new VerifyCS.Test { TestState = @@ -180,8 +188,7 @@ public async Task GeneratedCodeFile_NoDiagnosticAsync() [Fact] public async Task AutoGeneratedComment_NoDiagnosticAsync() { - // Entry point file without shebang, but the second file has an comment, - // so there is effectively only one non-generated file - no diagnostic. + // Entry point file without shebang, but no #:include directive - no diagnostic. await new VerifyCS.Test { TestState = @@ -203,15 +210,17 @@ public async Task AutoGeneratedComment_NoDiagnosticAsync() [Fact] public async Task GeneratedCodePlusRealFile_WarningAsync() { - // Entry point file without shebang, a real second file, and a generated file. - // Two non-generated files exist, so a warning is expected. + // Entry point file without shebang and a #:include directive - warning expected. await new VerifyCS.Test { TestState = { Sources = { - ("Test0.cs", """class Program { static void Main() { } }"""), + ("Test0.cs", """ + #:include Util.cs + class Program { static void Main() { } } + """), ("Util.cs", """class Util { }"""), ("Test1.g.cs", """class Generated { }"""), }, @@ -221,6 +230,7 @@ public async Task GeneratedCodePlusRealFile_WarningAsync() new DiagnosticResult(MissingShebangInFileBasedProgram.Rule).WithLocation("Test0.cs", 1, 1), }, }, + SolutionTransforms = { EnableFileBasedProgramFeature }, }.RunAsync(TestContext.Current.CancellationToken); } @@ -236,6 +246,7 @@ public async Task ShebangNotAtPositionZero_WarningAsync() Sources = { ("Test0.cs", """ + #:include Util.cs class Foo { } #!/usr/bin/env dotnet class Program { static void Main() { } } @@ -247,20 +258,19 @@ class Program { static void Main() { } } { new DiagnosticResult(MissingShebangInFileBasedProgram.Rule).WithLocation("Test0.cs", 1, 1), // Test0.cs(2,1): error CS9378: '#!' must be the first characters on the first line of the file - DiagnosticResult.CompilerError("CS9378").WithSpan("Test0.cs", 2, 1, 2, 2), - }, - }, - SolutionTransforms = - { - (solution, projectId) => - { - var parseOptions = (CSharpParseOptions)solution.GetProject(projectId)!.ParseOptions!; - return solution.WithProjectParseOptions(projectId, - parseOptions.WithFeatures(parseOptions.Features.Concat( - [new KeyValuePair("FileBasedProgram", "true")]))); + DiagnosticResult.CompilerError("CS9378").WithSpan("Test0.cs", 3, 1, 3, 2), }, }, + SolutionTransforms = { EnableFileBasedProgramFeature }, }.RunAsync(TestContext.Current.CancellationToken); } + + private static Solution EnableFileBasedProgramFeature(Solution solution, ProjectId projectId) + { + var parseOptions = (CSharpParseOptions)solution.GetProject(projectId)!.ParseOptions!; + return solution.WithProjectParseOptions(projectId, + parseOptions.WithFeatures(parseOptions.Features.Concat( + [new KeyValuePair("FileBasedProgram", "true")]))); + } } } \ No newline at end of file diff --git a/src/RazorSdk/Tasks/EncodeRazorInputItem.cs b/src/RazorSdk/Tasks/EncodeRazorInputItem.cs index 2abfbbb853f2..79fee3153640 100644 --- a/src/RazorSdk/Tasks/EncodeRazorInputItem.cs +++ b/src/RazorSdk/Tasks/EncodeRazorInputItem.cs @@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks // Characters like {} in the filename cause issues with resolving the type. To work // around this, we encode everything before writing it to the editorconfig then decode // inside the Razor source generator. + [MSBuildMultiThreadableTask] public class EncodeRazorInputItem : Task { [Required] diff --git a/src/StaticWebAssetsSdk/Tasks/DiscoverDefaultScopedCssItems.cs b/src/StaticWebAssetsSdk/Tasks/DiscoverDefaultScopedCssItems.cs index f946e4a58a51..d758e82ff0ea 100644 --- a/src/StaticWebAssetsSdk/Tasks/DiscoverDefaultScopedCssItems.cs +++ b/src/StaticWebAssetsSdk/Tasks/DiscoverDefaultScopedCssItems.cs @@ -7,6 +7,7 @@ namespace Microsoft.AspNetCore.StaticWebAssets.Tasks; +[MSBuildMultiThreadableTask] public class DiscoverDefaultScopedCssItems : Task { [Required] diff --git a/src/StaticWebAssetsSdk/Tasks/ReadPackageAssetsManifest.cs b/src/StaticWebAssetsSdk/Tasks/ReadPackageAssetsManifest.cs index eede445e8e8b..ce5c5f598b63 100644 --- a/src/StaticWebAssetsSdk/Tasks/ReadPackageAssetsManifest.cs +++ b/src/StaticWebAssetsSdk/Tasks/ReadPackageAssetsManifest.cs @@ -46,7 +46,6 @@ public override bool Execute() foreach (var manifestItem in PackageManifests) { var manifestPath = manifestItem.ItemSpec; - var sourceId = manifestItem.GetMetadata("SourceId"); var packageRoot = manifestItem.GetMetadata("PackageRoot"); var contentRoot = manifestItem.GetMetadata("ContentRoot"); @@ -83,7 +82,7 @@ public override bool Execute() var endpointGroups = StaticWebAssetEndpointGroup.CreateEndpointGroups(manifest.Endpoints ?? []); var (_, includedEndpoints) = StaticWebAssetEndpointGroup.ComputeFilteredEndpoints(endpointGroups, excludedPaths); - if (!ResolveAssetsAndEndpoints(includedAssets, includedEndpoints, sourceId, packageRoot, contentRoot)) + if (!ResolveAssetsAndEndpoints(includedAssets, includedEndpoints, packageRoot, contentRoot)) { return false; } @@ -105,11 +104,9 @@ public override bool Execute() private bool ResolveAssetsAndEndpoints( List assets, List endpoints, - string sourceId, string packageRoot, string contentRoot) { - var fxDir = Path.Combine(IntermediateOutputPath, "fx", sourceId); var frameworkPaths = new Dictionary(OSPath.PathComparer); var normalizedContentRoot = StaticWebAsset.NormalizeContentRootPath(contentRoot); @@ -117,14 +114,19 @@ private bool ResolveAssetsAndEndpoints( { if (StaticWebAsset.SourceTypes.IsFramework(asset.SourceType)) { - var resolvedRelativePath = StaticWebAssetPathPattern.PathWithoutTokens(asset.RelativePath); - var destPath = Path.GetFullPath(Path.Combine(fxDir, resolvedRelativePath)); - frameworkPaths[asset.Identity] = destPath; - MaterializeFrameworkAsset(asset, packageRoot, fxDir, destPath); - if (Log.HasLoggedErrors) + // Materialize framework assets into the fx intermediate folder using the shared + // routine so they are transformed identically across all consumption paths + // (package manifest, P2P, and project). This clears AssetGroups so endpoint + // generation does not skip the materialized asset, and normalizes it. + var originalIdentity = asset.Identity; + asset.Identity = ResolvePath(packageRoot, asset.Identity); + var (materialized, _, _) = StaticWebAsset.MaterializeFrameworkAsset( + asset, IntermediateOutputPath, ProjectPackageId, ProjectBasePath, Log); + if (materialized is null || Log.HasLoggedErrors) { return false; } + frameworkPaths[originalIdentity] = materialized.Identity; } else { @@ -187,36 +189,6 @@ private StaticWebAssetPackageManifest ReadManifest(string manifestPath) return manifest; } - private void MaterializeFrameworkAsset( - StaticWebAsset asset, - string packageRoot, - string fxDir, - string destPath) - { - var sourcePath = ResolvePath(packageRoot, asset.Identity); - - if (!File.Exists(sourcePath)) - { - Log.LogError("Source file '{0}' does not exist for framework asset materialization.", sourcePath); - return; - } - - Directory.CreateDirectory(Path.GetDirectoryName(destPath)); - - if (!File.Exists(destPath) || File.GetLastWriteTimeUtc(sourcePath) > File.GetLastWriteTimeUtc(destPath)) - { - File.Copy(sourcePath, destPath, overwrite: true); - } - - asset.Identity = destPath; - asset.OriginalItemSpec = destPath; - asset.SourceType = StaticWebAsset.SourceTypes.Discovered; - asset.SourceId = ProjectPackageId; - asset.ContentRoot = StaticWebAsset.NormalizeContentRootPath(fxDir); - asset.BasePath = ProjectBasePath; - asset.AssetMode = StaticWebAsset.AssetModes.CurrentProject; - } - private static string ResolvePath(string packageRoot, string relativePath) { return Path.GetFullPath(Path.Combine(packageRoot, relativePath.Replace('/', Path.DirectorySeparatorChar))); diff --git a/src/StaticWebAssetsSdk/Tasks/StaticWebAssetsGeneratePackagePropsFile.cs b/src/StaticWebAssetsSdk/Tasks/StaticWebAssetsGeneratePackagePropsFile.cs index 59d3811deed3..f25a3f7c70af 100644 --- a/src/StaticWebAssetsSdk/Tasks/StaticWebAssetsGeneratePackagePropsFile.cs +++ b/src/StaticWebAssetsSdk/Tasks/StaticWebAssetsGeneratePackagePropsFile.cs @@ -9,7 +9,8 @@ namespace Microsoft.AspNetCore.StaticWebAssets.Tasks; -public class StaticWebAssetsGeneratePackagePropsFile : Task +[MSBuildMultiThreadableTask] +public class StaticWebAssetsGeneratePackagePropsFile : Task, IMultiThreadableTask { [Required] public string PropsFileImport { get; set; } @@ -19,8 +20,12 @@ public class StaticWebAssetsGeneratePackagePropsFile : Task [Required] public string BuildTargetPath { get; set; } + public TaskEnvironment TaskEnvironment { get; set; } = TaskEnvironment.Fallback; + public override bool Execute() { + AbsolutePath buildTargetPath = TaskEnvironment.GetAbsolutePath(BuildTargetPath); + var document = new XDocument(new XDeclaration("1.0", "utf-8", "yes")); var elements = (AdditionalImports ?? []).Select(e => e.ItemSpec).Prepend(PropsFileImport) .OrderBy(id => id, StringComparer.Ordinal); @@ -49,26 +54,26 @@ public override bool Execute() } var data = memoryStream.ToArray(); - WriteFile(data); + WriteFile(data, buildTargetPath); return !Log.HasLoggedErrors; } - private void WriteFile(byte[] data) + private void WriteFile(byte[] data, string buildTargetPath) { var dataHash = ComputeHash(data); - var fileExists = File.Exists(BuildTargetPath); - var existingFileHash = fileExists ? ComputeHash(File.ReadAllBytes(BuildTargetPath)) : ""; + var fileExists = File.Exists(buildTargetPath); + var existingFileHash = fileExists ? ComputeHash(File.ReadAllBytes(buildTargetPath)) : ""; if (!fileExists) { - Log.LogMessage(MessageImportance.Low, $"Creating file '{BuildTargetPath}' does not exist."); - File.WriteAllBytes(BuildTargetPath, data); + Log.LogMessage(MessageImportance.Low, $"Creating file '{BuildTargetPath}' because it does not exist."); + File.WriteAllBytes(buildTargetPath, data); } else if (!string.Equals(dataHash, existingFileHash, StringComparison.Ordinal)) { Log.LogMessage(MessageImportance.Low, $"Updating '{BuildTargetPath}' file because the hash '{dataHash}' is different from existing file hash '{existingFileHash}'."); - File.WriteAllBytes(BuildTargetPath, data); + File.WriteAllBytes(buildTargetPath, data); } else { diff --git a/src/Tasks/Common/ConflictResolution/FrameworkListReader.cs b/src/Tasks/Common/ConflictResolution/FrameworkListReader.cs index 09e76766836e..e58ffe084b38 100644 --- a/src/Tasks/Common/ConflictResolution/FrameworkListReader.cs +++ b/src/Tasks/Common/ConflictResolution/FrameworkListReader.cs @@ -9,6 +9,8 @@ namespace Microsoft.NET.Build.Tasks.ConflictResolution { class FrameworkListReader { + private static readonly object s_cacheLock = new(); + private IBuildEngine4 _buildEngine; public FrameworkListReader(IBuildEngine4 buildEngine) @@ -16,44 +18,41 @@ public FrameworkListReader(IBuildEngine4 buildEngine) _buildEngine = buildEngine; } - public IEnumerable GetConflictItems(string frameworkListPath, Logger log) + public IEnumerable GetConflictItems(AbsolutePath frameworkListPath, Logger log) { - if (frameworkListPath == null) - { - throw new ArgumentNullException(nameof(frameworkListPath)); - } - - if (!Path.IsPathRooted(frameworkListPath)) + if (!Path.IsPathRooted(frameworkListPath.OriginalValue)) { - throw new BuildErrorException(Strings.FrameworkListPathNotRooted, frameworkListPath); + throw new BuildErrorException(Strings.FrameworkListPathNotRooted, frameworkListPath.OriginalValue); } - // Need to include assembly name in the key here, since both Microsoft.NET.Build.Tasks and Microsoft.NET.Build.Extensions.Tasks share this code, // but can't share the types of the ConflictItem objects. string? assemblyName = typeof(FrameworkListReader).GetTypeInfo().Assembly.FullName; - string objectKey = $"{assemblyName}:{nameof(FrameworkListReader)}:{frameworkListPath}"; + string objectKey = $"{assemblyName}:{nameof(FrameworkListReader)}:{frameworkListPath.OriginalValue}"; IEnumerable result; - object existingConflictItems = _buildEngine.GetRegisteredTaskObject(objectKey, RegisteredTaskObjectLifetime.AppDomain); - - if (existingConflictItems == null) + lock (s_cacheLock) { - result = LoadConflictItems(frameworkListPath, log); + object existingConflictItems = _buildEngine.GetRegisteredTaskObject(objectKey, RegisteredTaskObjectLifetime.AppDomain); - _buildEngine.RegisterTaskObject(objectKey, result, RegisteredTaskObjectLifetime.AppDomain, true); - } - else - { - result = (IEnumerable)existingConflictItems; + if (existingConflictItems == null) + { + result = LoadConflictItems(frameworkListPath, log); + + _buildEngine.RegisterTaskObject(objectKey, result, RegisteredTaskObjectLifetime.AppDomain, true); + } + else + { + result = (IEnumerable)existingConflictItems; + } } return result; } - private static IEnumerable LoadConflictItems(string frameworkListPath, Logger log) + private static IEnumerable LoadConflictItems(AbsolutePath frameworkListPath, Logger log) { if (!File.Exists(frameworkListPath)) { @@ -79,7 +78,7 @@ private static IEnumerable LoadConflictItems(string frameworkListP if (string.IsNullOrEmpty(assemblyName)) { string errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.ErrorParsingFrameworkListInvalidValue, - frameworkListPath, + frameworkListPath.OriginalValue, "AssemblyName", assemblyName); log.LogError(errorMessage); @@ -90,7 +89,7 @@ private static IEnumerable LoadConflictItems(string frameworkListP if (string.IsNullOrEmpty(assemblyVersionString) || !Version.TryParse(assemblyVersionString, out assemblyVersion)) { string errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.ErrorParsingFrameworkListInvalidValue, - frameworkListPath, + frameworkListPath.OriginalValue, "Version", assemblyVersionString); log.LogError(errorMessage); diff --git a/src/Tasks/Common/ConflictResolution/PlatformManifestReader.cs b/src/Tasks/Common/ConflictResolution/PlatformManifestReader.cs index 8076917cd7c3..12e0c1d4b72a 100644 --- a/src/Tasks/Common/ConflictResolution/PlatformManifestReader.cs +++ b/src/Tasks/Common/ConflictResolution/PlatformManifestReader.cs @@ -2,28 +2,29 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; +using Microsoft.Build.Framework; namespace Microsoft.NET.Build.Tasks.ConflictResolution { static class PlatformManifestReader { static readonly char[] s_manifestLineSeparator = new[] { '|' }; - public static IEnumerable LoadConflictItems(string manifestPath, Logger log) + public static IEnumerable LoadConflictItems(AbsolutePath? manifestPath, Logger log) { - if (manifestPath == null) + if (manifestPath is not AbsolutePath path) { throw new ArgumentNullException(nameof(manifestPath)); } - if (!File.Exists(manifestPath)) + if (!File.Exists(path)) { string errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.CouldNotLoadPlatformManifest, - manifestPath); + path.OriginalValue); log.LogError(errorMessage); yield break; } - using (var manifestStream = File.Open(manifestPath, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) + using (var manifestStream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) using (var manifestReader = new StreamReader(manifestStream)) { for (int lineNumber = 0; !manifestReader.EndOfStream; lineNumber++) @@ -40,7 +41,7 @@ public static IEnumerable LoadConflictItems(string manifestPath, L if (lineParts.Length != 4) { string errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.ErrorParsingPlatformManifest, - manifestPath, + path.OriginalValue, lineNumber, "fileName|packageId|assemblyVersion|fileVersion"); log.LogError(errorMessage); @@ -57,7 +58,7 @@ public static IEnumerable LoadConflictItems(string manifestPath, L if (assemblyVersionString.Length != 0 && !Version.TryParse(assemblyVersionString, out assemblyVersion)) { string errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.ErrorParsingPlatformManifestInvalidValue, - manifestPath, + path.OriginalValue, lineNumber, "AssemblyVersion", assemblyVersionString); @@ -67,7 +68,7 @@ public static IEnumerable LoadConflictItems(string manifestPath, L if (fileVersionString.Length != 0 && !Version.TryParse(fileVersionString, out fileVersion)) { string errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.ErrorParsingPlatformManifestInvalidValue, - manifestPath, + path.OriginalValue, lineNumber, "FileVersion", fileVersionString); diff --git a/src/Tasks/Common/ConflictResolution/ResolvePackageFileConflicts.cs b/src/Tasks/Common/ConflictResolution/ResolvePackageFileConflicts.cs index e083c300e996..34b3657ef23d 100644 --- a/src/Tasks/Common/ConflictResolution/ResolvePackageFileConflicts.cs +++ b/src/Tasks/Common/ConflictResolution/ResolvePackageFileConflicts.cs @@ -1,13 +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 System.Globalization; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace Microsoft.NET.Build.Tasks.ConflictResolution { - public class ResolvePackageFileConflicts : TaskBase + [MSBuildMultiThreadableTask] + public class ResolvePackageFileConflicts : TaskBase, IMultiThreadableTask { + public TaskEnvironment TaskEnvironment { get; set; } = TaskEnvironment.Fallback; + private HashSet referenceConflicts = new(); private HashSet analyzerConflicts = new(); private HashSet copyLocalConflicts = new(); @@ -69,7 +73,8 @@ protected override void ExecuteCore() compilePlatformItems = TargetFrameworkDirectories.SelectMany(tfd => { - return frameworkListReader.GetConflictItems(Path.Combine(tfd.ItemSpec, "RedistList", "FrameworkList.xml"), log); + AbsolutePath frameworkListPath = TaskEnvironment.GetAbsolutePath(Path.Combine(tfd.ItemSpec, "RedistList", "FrameworkList.xml")); + return frameworkListReader.GetConflictItems(frameworkListPath, log); }).ToArray(); } @@ -128,7 +133,17 @@ protected override void ExecuteCore() // we only commit the platform items since its not a conflict if other items share the same filename. using (var platformConflictScope = new ConflictResolver(packageRanks, packageOverrides, log)) { - var platformItems = PlatformManifests?.SelectMany(pm => PlatformManifestReader.LoadConflictItems(pm.ItemSpec, log)) ?? Enumerable.Empty(); + var platformItems = PlatformManifests?.SelectMany(pm => + { + if (string.IsNullOrEmpty(pm.ItemSpec)) + { + log.LogError(string.Format(CultureInfo.CurrentCulture, Strings.CouldNotLoadPlatformManifest, pm.ItemSpec)); + return Enumerable.Empty(); + } + + AbsolutePath manifestPath = TaskEnvironment.GetAbsolutePath(pm.ItemSpec); + return PlatformManifestReader.LoadConflictItems(manifestPath, log); + }) ?? Enumerable.Empty(); if (compilePlatformItems != null) { @@ -227,7 +242,7 @@ private ITaskItem CreateConflictTaskItem(ConflictItem conflict) private IEnumerable GetConflictTaskItems(ITaskItem[]? items, ConflictItemType itemType) { - return (items != null) ? items.Select(i => new ConflictItem(i, itemType, taskEnvironment: null)) : Enumerable.Empty(); + return (items != null) ? items.Select(i => new ConflictItem(i, itemType, TaskEnvironment)) : Enumerable.Empty(); } private void HandleCompileConflict(ConflictItem winner, ConflictItem loser) diff --git a/src/Tasks/Common/Resources/Strings.resx b/src/Tasks/Common/Resources/Strings.resx index b087f2cfd035..43238261dc2c 100644 --- a/src/Tasks/Common/Resources/Strings.resx +++ b/src/Tasks/Common/Resources/Strings.resx @@ -1038,5 +1038,9 @@ You may need to build the project on another operating system or architecture, o NETSDK1240: The current .NET SDK ({0}) has no newer release in its feature band. Update to version {1}: https://dotnet.microsoft.com/download {StrBegins="NETSDK1240: "}{Locked="{0}"}{Locked="{1}"} - + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + + diff --git a/src/Tasks/Common/Resources/xlf/Strings.cs.xlf b/src/Tasks/Common/Resources/xlf/Strings.cs.xlf index bec03e35e9d0..43ccbf127c24 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.cs.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.cs.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: Cílová architektura {0} se nepodporuje a v budoucnu už nebude dostávat aktualizace zabezpečení. Další informace o zásadách podpory najdete tady: {1} diff --git a/src/Tasks/Common/Resources/xlf/Strings.de.xlf b/src/Tasks/Common/Resources/xlf/Strings.de.xlf index 921007586138..e8328b93778e 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.de.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.de.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: Das Zielframework "{0}" wird nicht mehr unterstützt und erhält in Zukunft keine Sicherheitsupdates mehr. Weitere Informationen zur Supportrichtlinie finden Sie unter "{1}". diff --git a/src/Tasks/Common/Resources/xlf/Strings.es.xlf b/src/Tasks/Common/Resources/xlf/Strings.es.xlf index 0061c5426411..900f47a51428 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.es.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.es.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: La plataforma de destino "{0}" no tiene soporte técnico y no recibirá actualizaciones de seguridad en el futuro. Para obtener más información sobre la directiva de soporte técnico, consulte {1}. diff --git a/src/Tasks/Common/Resources/xlf/Strings.fr.xlf b/src/Tasks/Common/Resources/xlf/Strings.fr.xlf index aa5116db7d3d..5ad47b875300 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.fr.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.fr.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: La version cible de .NET Framework ('{0}') n'est pas prise en charge et ne recevra pas les mises à jour de sécurité. Consultez {1} pour plus d'informations sur la stratégie de support. diff --git a/src/Tasks/Common/Resources/xlf/Strings.it.xlf b/src/Tasks/Common/Resources/xlf/Strings.it.xlf index 41f122fd3325..a389beb4801a 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.it.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.it.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: il framework di destinazione '{0}' non è più supportato e non riceverà aggiornamenti della sicurezza in futuro. Per altre informazioni sui criteri di supporto, vedere {1}. diff --git a/src/Tasks/Common/Resources/xlf/Strings.ja.xlf b/src/Tasks/Common/Resources/xlf/Strings.ja.xlf index 9f485768c6aa..f9503e380eb3 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.ja.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.ja.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: ターゲット フレームワーク '{0}' はサポートされていません。今後、セキュリティ更新プログラムを受け取ることはありません。サポート ポリシーの詳細については、{1} をご覧ください。 diff --git a/src/Tasks/Common/Resources/xlf/Strings.ko.xlf b/src/Tasks/Common/Resources/xlf/Strings.ko.xlf index bf3dd8748679..69f1eafad9a0 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.ko.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.ko.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: 대상 프레임워크 '{0}'은(는) 지원되지 않으며 향후 보안 업데이트를 받을 수 없습니다. 지원 정책에 대한 자세한 내용은 {1}을(를) 참조하세요. diff --git a/src/Tasks/Common/Resources/xlf/Strings.pl.xlf b/src/Tasks/Common/Resources/xlf/Strings.pl.xlf index 8e96ce30b670..4f6e110a4890 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.pl.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.pl.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: platforma docelowa „{0}” nie jest już obsługiwana i w przyszłości nie będzie otrzymywać aktualizacji zabezpieczeń. Aby uzyskać więcej informacji na temat zasad pomocy technicznej, zobacz {1}. diff --git a/src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf b/src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf index 64fa415d360e..0095c67fa9e1 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.pt-BR.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: não há mais suporte para a estrutura de destino '{0}' e ela não receberá atualizações de segurança no futuro. Confira {1} para obter mais informações sobre a política de suporte. diff --git a/src/Tasks/Common/Resources/xlf/Strings.ru.xlf b/src/Tasks/Common/Resources/xlf/Strings.ru.xlf index 3622104494ab..1851952a22d1 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.ru.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.ru.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: целевая платформа "{0}" больше не поддерживается и не будет получать обновления для системы безопасности в будущем. Дополнительные сведения о политике поддержки см. в {1}. diff --git a/src/Tasks/Common/Resources/xlf/Strings.tr.xlf b/src/Tasks/Common/Resources/xlf/Strings.tr.xlf index 3d8e1806d88e..3da87825a7d6 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.tr.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.tr.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: '{0}' hedef çerçevesi destek kapsamı dışında ve gelecekte güvenlik güncelleştirmeleri almayacak. Lütfen destek ilkesi hakkında daha fazla bilgi için şuraya bakın: {1}. diff --git a/src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf b/src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf index 28d4feb0e34f..4c6dcd3e280b 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.zh-Hans.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: 目标框架“{0}”不受支持,将来不会收到安全更新。有关支持策略的详细信息,请参阅 {1}。 diff --git a/src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf b/src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf index 1835e69bdcdb..19a95ec40865 100644 --- a/src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Tasks/Common/Resources/xlf/Strings.zh-Hant.xlf @@ -958,6 +958,11 @@ The following are names of parameters or literal values and should not be transl {1} {StrBegins="NETSDK1197: "} + + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + NETSDK1241: The TargetFramework property is empty. Specify a value for the TargetFramework property in your project file. + {StrBegins="NETSDK1241: "} + NETSDK1138: The target framework '{0}' is out of support and will not receive security updates in the future. Please refer to {1} for more information about the support policy. NETSDK1138: 目標 Framework '{0}' 已不受支援,未來將不會再收到任何安全性更新。如需支援原則的詳細資訊,請參閱 {1}。 diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/CheckForUnsupportedWinMDReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/CheckForUnsupportedWinMDReferences.cs index 044a6e3e029b..7a145791f75d 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/CheckForUnsupportedWinMDReferences.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/CheckForUnsupportedWinMDReferences.cs @@ -11,8 +11,11 @@ namespace Microsoft.NET.Build.Tasks { // This task is used for projects targeting .NET 5 and higher and generates errors if there are any // unsupported WinMD references. - public class CheckForUnsupportedWinMDReferences : TaskBase + [MSBuildMultiThreadableTask] + public class CheckForUnsupportedWinMDReferences : TaskBase, IMultiThreadableTask { + public TaskEnvironment TaskEnvironment { get; set; } = TaskEnvironment.Fallback; + public string TargetFrameworkMoniker { get; set; } public ITaskItem[] ReferencePaths { get; set; } = Array.Empty(); @@ -49,7 +52,7 @@ protected override void ExecuteCore() foreach (var referencePath in ReferencePaths) { if (!Path.GetExtension(referencePath.ItemSpec).Equals(".winmd", StringComparison.OrdinalIgnoreCase) && - AssemblyHasWindowsRuntimeReference(referencePath.ItemSpec)) + AssemblyHasWindowsRuntimeReference(TaskEnvironment.GetAbsolutePath(referencePath.ItemSpec))) { // Ignore System.Runtime.WindowsRuntime.dll, as it has windowsruntime metadata references, but is a dependency of // the Microsoft.Windows.Sdk.Contracts package, so generating an error about it isn't helpful @@ -76,9 +79,9 @@ protected override void ExecuteCore() } - private static bool AssemblyHasWindowsRuntimeReference(string sourcePath) + private static bool AssemblyHasWindowsRuntimeReference(AbsolutePath sourcePath) { - using (var assemblyStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read)) + using (var assemblyStream = new FileStream(sourcePath.Value, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read)) { try { diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.cs b/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.cs index 91ac822a7165..d32a3c5700fd 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.cs @@ -13,6 +13,7 @@ namespace Microsoft.ComponentDetection.Detectors.NuGet; using System.Linq; using global::NuGet.Frameworks; using global::NuGet.Versioning; +using Microsoft.Build.Framework; using Microsoft.NET.Build.Tasks; using Microsoft.NET.Build.Tasks.ConflictResolution; @@ -115,33 +116,34 @@ public static FrameworkPackages[] GetFrameworkPackages(NuGetFramework framework, return frameworkPackages.ToArray(); } - public static FrameworkPackages LoadFrameworkPackagesFromPack(Logger log, NuGetFramework framework, string frameworkName, string targetingPackRoot) + public static FrameworkPackages LoadFrameworkPackagesFromPack(Logger log, NuGetFramework framework, string frameworkName, AbsolutePath targetingPackRoot) { if (framework is null || framework.Framework != FrameworkConstants.FrameworkIdentifiers.NetCoreApp) { return null; } - if (!string.IsNullOrEmpty(targetingPackRoot)) + if (!string.IsNullOrEmpty(targetingPackRoot.Value)) { var packsFolder = Path.Combine(targetingPackRoot, frameworkName + ".Ref"); - log.LogMessage("Looking for targeting packs in {0}", packsFolder); + var originalPacksFolder = Path.Combine(targetingPackRoot.OriginalValue, frameworkName + ".Ref"); + log.LogMessage("Looking for targeting packs in {0}", originalPacksFolder); if (Directory.Exists(packsFolder)) { var packVersionPattern = $"{framework.Version.Major}.{framework.Version.Minor}.*"; var packDirectories = Directory.GetDirectories(packsFolder, packVersionPattern); - log.LogMessage("Pack directories found: {0}", string.Join(Environment.NewLine, packDirectories)); - var packageOverridesFile = packDirectories - .Select(d => (Overrides: Path.Combine(d, "data", "PackageOverrides.txt"), Version: ParseVersion(Path.GetFileName(d)))) + log.LogMessage("Pack directories found: {0}", string.Join(Environment.NewLine, packDirectories.Select(d => Path.Combine(originalPacksFolder, Path.GetFileName(d))))); + var packageOverrides = packDirectories + .Select(d => (Overrides: Path.Combine(d, "data", "PackageOverrides.txt"), OriginalOverrides: Path.Combine(originalPacksFolder, Path.GetFileName(d), "data", "PackageOverrides.txt"), Version: ParseVersion(Path.GetFileName(d)))) .Where(d => File.Exists(d.Overrides)) .OrderByDescending(d => d.Version) - .FirstOrDefault().Overrides; + .FirstOrDefault(); - if (packageOverridesFile is not null) + if (packageOverrides.Overrides is not null) { - log.LogMessage("Found package overrides file {0}", packageOverridesFile); + log.LogMessage("Found package overrides file {0}", packageOverrides.OriginalOverrides); // Adapted from https://github.com/dotnet/sdk/blob/c3a8f72c3a5491c693ff8e49e7406136a12c3040/src/Tasks/Common/ConflictResolution/PackageOverride.cs#L52-L68 - var packageOverrideLines = File.ReadAllLines(packageOverridesFile); + var packageOverrideLines = File.ReadAllLines(packageOverrides.Overrides); var frameworkPackages = new FrameworkPackages(framework, frameworkName); foreach (var packageOverride in PackageOverride.CreateOverriddenPackages(packageOverrideLines)) @@ -153,12 +155,12 @@ public static FrameworkPackages LoadFrameworkPackagesFromPack(Logger log, NuGetF } else { - log.LogMessage("No package overrides found in {0}", packsFolder); + log.LogMessage("No package overrides found in {0}", originalPacksFolder); } } else { - log.LogMessage("Targeting pack folder {0} does not exist", packsFolder); + log.LogMessage("Targeting pack folder {0} does not exist", originalPacksFolder); } } diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/GetPackagesToPrune.cs b/src/Tasks/Microsoft.NET.Build.Tasks/GetPackagesToPrune.cs index c7cf14afb22d..acd3c88ca91b 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/GetPackagesToPrune.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/GetPackagesToPrune.cs @@ -12,8 +12,11 @@ namespace Microsoft.NET.Build.Tasks { - public class GetPackagesToPrune : TaskBase + [MSBuildMultiThreadableTask] + public class GetPackagesToPrune : TaskBase, IMultiThreadableTask { + public TaskEnvironment TaskEnvironment { get; set; } = TaskEnvironment.Fallback; + // Minimum .NET Core version that supports package pruning private const int FrameworkReferenceMinVersion = 3; @@ -60,34 +63,58 @@ class CacheKey public string TargetFrameworkVersion { get; set; } public HashSet FrameworkReferences { get; set; } public bool LoadPrunePackageDataFromNearestFramework { get; set; } + public bool AllowMissingPrunePackageData { get; set; } + + // The resolved (absolutized) prune package data root and targeting pack roots are part of the cache key. + // Otherwise two projects with the same framework values but different resolved roots (for example, the same + // project-relative path under different TaskEnvironment.ProjectDirectory values) could incorrectly reuse the + // first project's package data from the build-wide cache. + public string PrunePackageDataRoot { get; set; } + // Targeting pack roots are a search path, so their order can affect which pack is loaded. + public string[] TargetingPackRoots { get; set; } public override bool Equals(object obj) => obj is CacheKey key && TargetFrameworkIdentifier == key.TargetFrameworkIdentifier && TargetFrameworkVersion == key.TargetFrameworkVersion && FrameworkReferences.SetEquals(key.FrameworkReferences) && - LoadPrunePackageDataFromNearestFramework == key.LoadPrunePackageDataFromNearestFramework; + LoadPrunePackageDataFromNearestFramework == key.LoadPrunePackageDataFromNearestFramework && + AllowMissingPrunePackageData == key.AllowMissingPrunePackageData && + PrunePackageDataRoot == key.PrunePackageDataRoot && + TargetingPackRoots.SequenceEqual(key.TargetingPackRoots); public override int GetHashCode() { #if NET var hashCode = new HashCode(); hashCode.Add(TargetFrameworkIdentifier); hashCode.Add(TargetFrameworkVersion); - foreach (var frameworkReference in FrameworkReferences) + foreach (var frameworkReference in FrameworkReferences.OrderBy(r => r, StringComparer.Ordinal)) { hashCode.Add(frameworkReference); } hashCode.Add(LoadPrunePackageDataFromNearestFramework); + hashCode.Add(AllowMissingPrunePackageData); + hashCode.Add(PrunePackageDataRoot); + foreach (var targetingPackRoot in TargetingPackRoots) + { + hashCode.Add(targetingPackRoot); + } return hashCode.ToHashCode(); #else int hashCode = 1436330440; hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(TargetFrameworkIdentifier); hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(TargetFrameworkVersion); - foreach (var frameworkReference in FrameworkReferences) + foreach (var frameworkReference in FrameworkReferences.OrderBy(r => r, StringComparer.Ordinal)) { hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(frameworkReference); } hashCode = hashCode * -1521134295 + LoadPrunePackageDataFromNearestFramework.GetHashCode(); + hashCode = hashCode * -1521134295 + AllowMissingPrunePackageData.GetHashCode(); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(PrunePackageDataRoot); + foreach (var targetingPackRoot in TargetingPackRoots) + { + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(targetingPackRoot); + } return hashCode; #endif } @@ -118,15 +145,25 @@ protected override void ExecuteCore() } } + AbsolutePath prunePackageDataRoot = TaskEnvironment.GetAbsolutePath(PrunePackageDataRoot); + + AbsolutePath[] targetingPackRoots = TargetingPackRoots + .Where(r => !string.IsNullOrEmpty(r)) + .Select(r => TaskEnvironment.GetAbsolutePath(r)) + .ToArray(); + CacheKey key = new() { TargetFrameworkIdentifier = TargetFrameworkIdentifier, TargetFrameworkVersion = TargetFrameworkVersion, FrameworkReferences = runtimeFrameworks.ToHashSet(), - LoadPrunePackageDataFromNearestFramework = LoadPrunePackageDataFromNearestFramework + LoadPrunePackageDataFromNearestFramework = LoadPrunePackageDataFromNearestFramework, + AllowMissingPrunePackageData = AllowMissingPrunePackageData, + PrunePackageDataRoot = prunePackageDataRoot.Value, + TargetingPackRoots = targetingPackRoots.Select(r => r.Value).ToArray() }; - // Cache framework package values per build + // Cache framework package values per build. var existingResult = BuildEngine4.GetRegisteredTaskObject(key, RegisteredTaskObjectLifetime.Build); if (existingResult != null) { @@ -134,12 +171,12 @@ protected override void ExecuteCore() return; } - PackagesToPrune = LoadPackagesToPrune(key, TargetingPackRoots, PrunePackageDataRoot, Log, AllowMissingPrunePackageData); + PackagesToPrune = LoadPackagesToPrune(key, targetingPackRoots, prunePackageDataRoot, Log, AllowMissingPrunePackageData); BuildEngine4.RegisterTaskObject(key, PackagesToPrune, RegisteredTaskObjectLifetime.Build, true); } - static TaskItem[] LoadPackagesToPrune(CacheKey key, string[] targetingPackRoots, string prunePackageDataRoot, Logger log, bool allowMissingPrunePackageData) + static TaskItem[] LoadPackagesToPrune(CacheKey key, AbsolutePath[] targetingPackRoots, AbsolutePath prunePackageDataRoot, Logger log, bool allowMissingPrunePackageData) { Dictionary packagesToPrune = new(); @@ -225,7 +262,7 @@ static Dictionary LoadPackagesToPruneFromFrameworkPackages return frameworkPackages; } - static Dictionary LoadPackagesToPruneFromPrunePackageData(string targetFrameworkIdentifier, string targetFrameworkVersion, string frameworkReference, string prunePackageDataRoot) + static Dictionary LoadPackagesToPruneFromPrunePackageData(string targetFrameworkIdentifier, string targetFrameworkVersion, string frameworkReference, AbsolutePath prunePackageDataRoot) { string packageOverridesPath = Path.Combine(prunePackageDataRoot, targetFrameworkVersion, frameworkReference, "PackageOverrides.txt"); if (File.Exists(packageOverridesPath)) @@ -238,7 +275,7 @@ static Dictionary LoadPackagesToPruneFromPrunePackageData( return null; } - static Dictionary LoadPackagesToPruneFromTargetingPack(Logger log, string targetFrameworkIdentifier, string targetFrameworkVersion, string frameworkReference, string [] targetingPackRoots) + static Dictionary LoadPackagesToPruneFromTargetingPack(Logger log, string targetFrameworkIdentifier, string targetFrameworkVersion, string frameworkReference, AbsolutePath[] targetingPackRoots) { var nugetFramework = new NuGetFramework(targetFrameworkIdentifier, Version.Parse(targetFrameworkVersion)); @@ -256,7 +293,7 @@ static Dictionary LoadPackagesToPruneFromTargetingPack(Log return null; } - static Dictionary TryLoadPackagesToPruneForVersion(Logger log, string targetFrameworkIdentifier, string targetFrameworkVersion, string frameworkReference, string[] targetingPackRoots, string prunePackageDataRoot, bool loadPrunePackageDataFromNearestFramework) + static Dictionary TryLoadPackagesToPruneForVersion(Logger log, string targetFrameworkIdentifier, string targetFrameworkVersion, string frameworkReference, AbsolutePath[] targetingPackRoots, AbsolutePath prunePackageDataRoot, bool loadPrunePackageDataFromNearestFramework) { var currentVersion = Version.Parse(targetFrameworkVersion); diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/PickBestRid.cs b/src/Tasks/Microsoft.NET.Build.Tasks/PickBestRid.cs index c0e02ef0b30b..10cd37c439ea 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/PickBestRid.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/PickBestRid.cs @@ -9,8 +9,10 @@ namespace Microsoft.NET.Build.Tasks; /// /// This task uses the given RID graph in a given SDK to pick the best match from among a set of supported RIDs for the current RID /// -public sealed class PickBestRid : TaskBase +[MSBuildMultiThreadableTask] +public sealed class PickBestRid : TaskBase, IMultiThreadableTask { + public TaskEnvironment TaskEnvironment { get; set; } = TaskEnvironment.Fallback; /// /// The path to the RID graph to read /// @@ -37,13 +39,20 @@ public sealed class PickBestRid : TaskBase protected override void ExecuteCore() { - if (!File.Exists(RuntimeGraphPath)) + if (string.IsNullOrEmpty(RuntimeGraphPath)) { Log.LogError(Strings.RuntimeGraphFileDoesNotExist, RuntimeGraphPath); return; } - RuntimeGraph graph = new RuntimeGraphCache(this).GetRuntimeGraph(RuntimeGraphPath); + AbsolutePath runtimeGraphPath = TaskEnvironment.GetAbsolutePath(RuntimeGraphPath); + if (!File.Exists(runtimeGraphPath)) + { + Log.LogError(Strings.RuntimeGraphFileDoesNotExist, RuntimeGraphPath); + return; + } + + RuntimeGraph graph = new RuntimeGraphCache(this).GetRuntimeGraph(runtimeGraphPath); var bestRidForPlatform = NuGetUtils.GetBestMatchingRid(graph, TargetRid, SupportedRids, out bool wasInGraph); if (!wasInGraph || bestRidForPlatform == null) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/RuntimeGraphCache.cs b/src/Tasks/Microsoft.NET.Build.Tasks/RuntimeGraphCache.cs index 6f366775c15d..5967d86d5cf9 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/RuntimeGraphCache.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/RuntimeGraphCache.cs @@ -3,6 +3,7 @@ #nullable disable +using System.Collections.Concurrent; using Microsoft.Build.Framework; using NuGet.RuntimeModel; @@ -10,6 +11,8 @@ namespace Microsoft.NET.Build.Tasks { internal class RuntimeGraphCache { + private static readonly ConcurrentDictionary s_keyLocks = new(); + private IBuildEngine4 _buildEngine; private Logger _log; @@ -32,20 +35,24 @@ public RuntimeGraph GetRuntimeGraph(string runtimeJsonPath) string key = GetTaskObjectKey(runtimeJsonPath); - RuntimeGraph result; - object existingRuntimeGraphTaskObject = _buildEngine.GetRegisteredTaskObject(key, RegisteredTaskObjectLifetime.AppDomain); - if (existingRuntimeGraphTaskObject == null) + object keyLock = s_keyLocks.GetOrAdd(key, static _ => new object()); + lock (keyLock) { - result = JsonRuntimeFormat.ReadRuntimeGraph(runtimeJsonPath); - - _buildEngine.RegisterTaskObject(key, result, RegisteredTaskObjectLifetime.AppDomain, true); + RuntimeGraph result; + object existingRuntimeGraphTaskObject = _buildEngine.GetRegisteredTaskObject(key, RegisteredTaskObjectLifetime.AppDomain); + if (existingRuntimeGraphTaskObject == null) + { + result = JsonRuntimeFormat.ReadRuntimeGraph(runtimeJsonPath); + + _buildEngine.RegisterTaskObject(key, result, RegisteredTaskObjectLifetime.AppDomain, true); + } + else + { + result = (RuntimeGraph)existingRuntimeGraphTaskObject; + } + + return result; } - else - { - result = (RuntimeGraph)existingRuntimeGraphTaskObject; - } - - return result; } private static string GetTaskObjectKey(string runtimeJsonPath) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets index 66dda45cf7ca..9b808caf3962 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets @@ -33,23 +33,11 @@ Copyright (c) .NET Foundation. All rights reserved. false false - true - true - true - true - true - - true - true - true - true - true - - true - true - true - true - true + true + + true + + true $(PublishReadyToRunCrossgen2ExtraArgs);--strip-inlining-info $(PublishReadyToRunCrossgen2ExtraArgs);--strip-debug-info 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 84059ae093f1..57f788beea24 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 @@ -106,7 +106,10 @@ Copyright (c) .NET Foundation. All rights reserved. BeforeTargets="_CheckForInvalidConfigurationAndPlatform;RunResolvePackageDependencies;GetFrameworkPaths;GetReferenceAssemblyPaths;Restore" Condition="'$(_UnsupportedTargetFrameworkError)' == 'true'" > - + + diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-CSharp-Item/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-CSharp-Item/.template.config/template.json index 4af7b9e8ecce..bc5e11809744 100644 --- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-CSharp-Item/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-CSharp-Item/.template.config/template.json @@ -3,7 +3,7 @@ "author": "Aleksei Kharlov aka halex2005 (codeofclimber.ru)", "classifications": [ "Test", "NUnit" ], "name": "NUnit Test Item", - "defaultName": "NUnitTestItem", + "defaultName": "UnitTest1", "generatorVersions": "[1.0.0.0-*)", "description": "Creates a new NUnit test class", "groupIdentity": "NUnit3.DotNetNew.ItemTemplate", @@ -15,7 +15,7 @@ "type": "item" }, "sourceName": "UnitTest1", - "preferNameDirectory": true, + "preferDefaultName": true, "primaryOutputs": [ { "path": "UnitTest1.cs" } ], diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-FSharp-Item/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-FSharp-Item/.template.config/template.json index c12fcfb0e4fd..3c449c815cfa 100644 --- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-FSharp-Item/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-FSharp-Item/.template.config/template.json @@ -3,7 +3,7 @@ "author": "Aleksei Kharlov aka halex2005 (codeofclimber.ru)", "classifications": [ "Test", "NUnit" ], "name": "NUnit Test Item", - "defaultName": "NUnitTestItem", + "defaultName": "UnitTest1", "generatorVersions": "[1.0.0.0-*)", "description": "Creates a new NUnit test class", "groupIdentity": "NUnit3.DotNetNew.ItemTemplate", @@ -15,7 +15,7 @@ "type": "item" }, "sourceName": "UnitTest1", - "preferNameDirectory": true, + "preferDefaultName": true, "primaryOutputs": [ { "path": "UnitTest1.fs" } ], diff --git a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-VisualBasic-Item/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-VisualBasic-Item/.template.config/template.json index af92027aa85c..50a327c2a383 100644 --- a/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-VisualBasic-Item/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ItemTemplates/content/NUnit-VisualBasic-Item/.template.config/template.json @@ -3,7 +3,7 @@ "author": "Aleksei Kharlov aka halex2005 (codeofclimber.ru)", "classifications": [ "Test", "NUnit" ], "name": "NUnit Test Item", - "defaultName": "NUnitTestItem", + "defaultName": "UnitTest1", "generatorVersions": "[1.0.0.0-*)", "description": "Creates a new NUnit test class", "groupIdentity": "NUnit3.DotNetNew.ItemTemplate", @@ -15,7 +15,7 @@ "type": "item" }, "sourceName": "UnitTest1", - "preferNameDirectory": true, + "preferDefaultName": true, "primaryOutputs": [ { "path": "UnitTest1.vb" } ], diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/dotnetcli.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/dotnetcli.host.json index 8cb77b63f5c4..844fa7e089ed 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/dotnetcli.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/dotnetcli.host.json @@ -29,6 +29,10 @@ "shortName": "", "longName": "extensions-profile" }, + "ExplicitProgramFile": { + "shortName": "", + "longName": "explicit-program-file" + }, "Fixture" : { "shortName": "", "longName": "fixture" diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/ide.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/ide.host.json index bdd89182698f..7de07642399e 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/ide.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/ide.host.json @@ -16,6 +16,11 @@ "id": "ExtensionsProfile", "isVisible": true }, + { + "id": "ExplicitProgramFile", + "isVisible": true, + "persistenceScope": "shared" + }, { "id": "CoverageTool", "isVisible": true, diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.cs.json index ae23dc015845..822faddb2c7f 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.cs.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.cs.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Žádné", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Povolit všechna rozšíření odeslaná Microsoftem (včetně rozšíření s omezující licencí)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "Vyberte typy testovacích součástí, které se mají zahrnout do projektu.", "symbols/Fixture/displayName": "Testovací přípravek", "symbols/Fixture/choices/None/description": "Žádné metody testovacího přípravku", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.de.json index 0a8cd0dab24f..1fdcfc20cf79 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.de.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.de.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Keine", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Alle von Microsoft gelieferten Erweiterungen aktivieren (einschließlich Erweiterungen mit einer restriktiven Lizenz)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "Wählen Sie die Fixturearten aus, die in das Projekt eingeschlossen werden sollen.", "symbols/Fixture/displayName": "Fixture", "symbols/Fixture/choices/None/description": "Keine Fixturemethoden", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.en.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.en.json index 8d2859b5db31..f9ad815d3eb6 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.en.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.en.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "None", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Enable all extensions shipped by Microsoft (including extensions with a restrictive license)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "Select the fixture kinds to include in the project.", "symbols/Fixture/displayName": "Fixture", "symbols/Fixture/choices/None/description": "No fixture methods", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.es.json index 20e634ab69d9..be4d0fbe63ad 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.es.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.es.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Ninguno", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Habilitar todas las extensiones enviadas por Microsoft (incluidas las extensiones con una licencia restrictiva)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "Seleccione los tipos de accesorio que desea incluir en el proyecto.", "symbols/Fixture/displayName": "Accesorio", "symbols/Fixture/choices/None/description": "No hay métodos de accesorio", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.fr.json index e5bfc07e0f75..5500a1869c47 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.fr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.fr.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Aucun", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Activez toutes les extensions fournies par Microsoft (y compris les extensions avec une licence restrictive)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "Sélectionnez les types de fixtures à inclure dans le projet.", "symbols/Fixture/displayName": "Appareil", "symbols/Fixture/choices/None/description": "Aucune méthode de fixture", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.it.json index 8e659ed1a3af..83e014f43e39 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.it.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.it.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Nessuno", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Abilita tutte le estensioni spedite da Microsoft (incluse le estensioni con una licenza restrittiva)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "Selezionare i tipi di fixture da includere nel progetto.", "symbols/Fixture/displayName": "Fixture", "symbols/Fixture/choices/None/description": "Nessun metodo di fixture", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ja.json index c13c6064b9be..27ba91fa5867 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ja.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ja.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "なし", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Microsoft が出荷するすべての拡張機能を有効にする (制限付きライセンスを持つ拡張機能を含む)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "プロジェクトに含めるフィクスチャの種類を選択します。", "symbols/Fixture/displayName": "フィクスチャ", "symbols/Fixture/choices/None/description": "フィクスチャ メソッドがありません", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ko.json index 84a56314d769..d34c6e15cd3c 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ko.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ko.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "없음", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Microsoft에서 제공하는 모든 확장 사용(제한 라이선스가 있는 확장 포함)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "프로젝트에 포함할 픽스쳐 종류를 선택합니다.", "symbols/Fixture/displayName": "픽스쳐", "symbols/Fixture/choices/None/description": "픽스쳐 메서드 없음", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pl.json index d314c5603fce..f8098789bb8d 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pl.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pl.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Brak", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Włącz wszystkie rozszerzenia dostarczane przez firmę Microsoft (w tym rozszerzenia z restrykcyjną licencją)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "Wybierz rodzaje warunków początkowych do uwzględnienia w projekcie.", "symbols/Fixture/displayName": "Warunki początkowe", "symbols/Fixture/choices/None/description": "Brak metod początkowych", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json index 16ee91c27451..194bd06eb365 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Nenhum", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Habilitar todas as extensões enviadas pela Microsoft (incluindo extensões com uma licença restritiva)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "Selecione os tipos de acessório a serem incluídos no projeto.", "symbols/Fixture/displayName": "Acessório", "symbols/Fixture/choices/None/description": "Nenhum método de acessório", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ru.json index c81379a05fc0..75ccdc237143 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ru.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.ru.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Отсутствует", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Включить все расширения, поставляемые Майкрософт (включая расширения с ограничительной лицензией)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "Выберите типы средств, которые необходимо включить в проект.", "symbols/Fixture/displayName": "Средство", "symbols/Fixture/choices/None/description": "Нет методов работы со средствами", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.tr.json index 0b8fca76413c..9b21a0f162c3 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.tr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.tr.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Hiçbiri", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Microsoft'un gönderdiği tüm uzantıları etkinleştir (kısıtlayıcı lisansı olan uzantılar dahil)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "Projeye dahil edilecek düzen türlerini seçin.", "symbols/Fixture/displayName": "Düzen", "symbols/Fixture/choices/None/description": "Düzen yöntemi yok", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json index 601e33f073d5..2b55f3a6ffc4 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "无", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "启用 Microsoft 提供的所有扩展(包括具有限制性许可证的扩展)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "选择要包含在项目中的固定例程类型。", "symbols/Fixture/displayName": "固定例程", "symbols/Fixture/choices/None/description": "无固定例程方法", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 11a1574526c9..1e7e26216d7b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "無", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "啟用由 Microsoft 提供的所有延伸模組 (包括具有有限制授權的延伸模組)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.cs file", "symbols/Fixture/description": "選取要併入專案中的固件類型。", "symbols/Fixture/displayName": "固件", "symbols/Fixture/choices/None/description": "沒有固件方法", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/template.json index 4fa231e893c9..338fefadf70f 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/.template.config/template.json @@ -97,10 +97,57 @@ "type": "parameter", "datatype": "text", "description": "Sets the LangVersion property in the created project file", - "defaultValue": "latest", + "defaultValue": "", "replaces": "$(ProjectLanguageVersion)", "displayName": "Language version" }, + "netFramework": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^net4\\d", + "source": "Framework" + } + }, + "csharp9orOlder": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^(ISO-1|ISO-2|[1-7]|[8-9]|[8-9]\\.0|7\\.[0-3])$", + "source": "langVersion" + } + }, + "csharp7orOlder": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^(ISO-1|ISO-2|[1-7]|7\\.[0-3])$", + "source": "langVersion" + } + }, + "csharp10orLater": { + "type": "computed", + "value": "!csharp9orOlder" + }, + "csharp8orLater": { + "type": "computed", + "value": "!csharp7orOlder" + }, + "csharpFeature_ImplicitUsings": { + "type": "computed", + "value": "(netFramework != \"true\" || langVersion != \"\") && csharp10orLater == \"true\"" + }, + "csharpFeature_Nullable": { + "type": "computed", + "value": "(netFramework != \"true\" || langVersion != \"\") && csharp8orLater == \"true\"" + }, + "csharpFeature_FileScopedNamespaces": { + "type": "computed", + "value": "(netFramework != \"true\" || langVersion != \"\") && csharp10orLater == \"true\"" + }, "UseMSTestSdk": { "type": "parameter", "datatype": "bool", @@ -169,6 +216,13 @@ } ] }, + "ExplicitProgramFile": { + "type": "parameter", + "datatype": "bool", + "description": "When using Microsoft.Testing.Platform, generate an explicit Program.cs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "displayName": "Use explicit Program.cs file", + "defaultValue": "false" + }, "Fixture": { "type": "parameter", "datatype": "choice", @@ -210,6 +264,16 @@ ] } }, + "sources": [ + { + "modifiers": [ + { + "condition": "(!ExplicitProgramFile || TestRunner != \"Microsoft.Testing.Platform\")", + "exclude": [ "Program.cs" ] + } + ] + } + ], "primaryOutputs": [ { "path": "Company.TestProject1.csproj" }, { diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Company.TestProject1.csproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Company.TestProject1.csproj index 9fd33170462b..a5f03948f9d8 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Company.TestProject1.csproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Company.TestProject1.csproj @@ -1,13 +1,13 @@  - + net11.0 TargetFrameworkOverride Company.TestProject1 $(ProjectLanguageVersion) - enable - enable + enable + enable true @@ -19,6 +19,9 @@ $(ExtensionsProfile) + + false + @@ -31,11 +34,14 @@ TargetFrameworkOverride Company.TestProject1 $(ProjectLanguageVersion) - enable - enable + enable + enable true Exe + + false + @@ -43,12 +49,14 @@ - + + + diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/MSTestSettings.cs b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/MSTestSettings.cs index aaf278c844f0..ed04ed055494 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/MSTestSettings.cs +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/MSTestSettings.cs @@ -1 +1,5 @@ -[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] +#if (!csharpFeature_ImplicitUsings) +using Microsoft.VisualStudio.TestTools.UnitTesting; + +#endif +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Program.cs b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Program.cs new file mode 100644 index 000000000000..76ad442dd28d --- /dev/null +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Program.cs @@ -0,0 +1,38 @@ +#if (!csharpFeature_ImplicitUsings) +using Microsoft.Testing.Platform.Builder; +using System.Threading.Tasks; + +#else +using Microsoft.Testing.Platform.Builder; + +#endif +#if (csharpFeature_FileScopedNamespaces) +namespace Company.TestProject1; + +internal static class Program +{ + public static async Task Main(string[] args) + { + ITestApplicationBuilder builder = await TestApplication.CreateBuilderAsync(args); + SelfRegisteredExtensions.AddSelfRegisteredExtensions(builder, args); + using ITestApplication app = await builder.BuildAsync(); + return await app.RunAsync(); + } +} +#else +namespace Company.TestProject1 +{ + internal static class Program + { + public static async Task Main(string[] args) + { + ITestApplicationBuilder builder = await TestApplication.CreateBuilderAsync(args); + SelfRegisteredExtensions.AddSelfRegisteredExtensions(builder, args); + using (ITestApplication app = await builder.BuildAsync()) + { + return await app.RunAsync(); + } + } + } +} +#endif diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Test1.cs b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Test1.cs index 9224c7fa9a7a..0a0732d1b985 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Test1.cs +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-CSharp/Test1.cs @@ -1,4 +1,9 @@ -namespace Company.TestProject1; +#if (!csharpFeature_ImplicitUsings) +using Microsoft.VisualStudio.TestTools.UnitTesting; + +#endif +#if (csharpFeature_FileScopedNamespaces) +namespace Company.TestProject1; [TestClass] public sealed class Test1 @@ -56,3 +61,64 @@ public void TestMethod1() { } } +#else +namespace Company.TestProject1 +{ + [TestClass] + public sealed class Test1 + { +#if (Fixture == AssemblyInitialize) + [AssemblyInitialize] + public static void AssemblyInit(TestContext context) + { + // This method is called once for the test assembly, before any tests are run. + } + +#endif +#if (Fixture == AssemblyCleanup) + [AssemblyCleanup] + public static void AssemblyCleanup() + { + // This method is called once for the test assembly, after all tests are run. + } + +#endif +#if (Fixture == ClassInitialize) + [ClassInitialize] + public static void ClassInit(TestContext context) + { + // This method is called once for the test class, before any tests of the class are run. + } + +#endif +#if (Fixture == ClassCleanup) + [ClassCleanup] + public static void ClassCleanup() + { + // This method is called once for the test class, after all tests of the class are run. + } + +#endif +#if (Fixture == TestInitialize) + [TestInitialize] + public void TestInit() + { + // This method is called before each test method. + } + +#endif +#if (Fixture == TestCleanup) + [TestCleanup] + public void TestCleanup() + { + // This method is called after each test method. + } + +#endif + [TestMethod] + public void TestMethod1() + { + } + } +} +#endif diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/dotnetcli.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/dotnetcli.host.json index 8cb77b63f5c4..844fa7e089ed 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/dotnetcli.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/dotnetcli.host.json @@ -29,6 +29,10 @@ "shortName": "", "longName": "extensions-profile" }, + "ExplicitProgramFile": { + "shortName": "", + "longName": "explicit-program-file" + }, "Fixture" : { "shortName": "", "longName": "fixture" diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/ide.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/ide.host.json index bdd89182698f..7de07642399e 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/ide.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/ide.host.json @@ -16,6 +16,11 @@ "id": "ExtensionsProfile", "isVisible": true }, + { + "id": "ExplicitProgramFile", + "isVisible": true, + "persistenceScope": "shared" + }, { "id": "CoverageTool", "isVisible": true, diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.cs.json index edcb1a90b19e..e19720295d89 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.cs.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.cs.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Žádné", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Povolit všechna rozšíření odeslaná Microsoftem (včetně rozšíření s omezující licencí)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "Vyberte typy testovacích součástí, které se mají zahrnout do projektu.", "symbols/Fixture/displayName": "Testovací přípravek", "symbols/Fixture/choices/None/description": "Žádné metody testovacího přípravku", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.de.json index 6c58a6e3d823..7985b03b1f40 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.de.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.de.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Keine", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Alle von Microsoft gelieferten Erweiterungen aktivieren (einschließlich Erweiterungen mit einer restriktiven Lizenz)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "Wählen Sie die Fixturearten aus, die in das Projekt eingeschlossen werden sollen.", "symbols/Fixture/displayName": "Fixture", "symbols/Fixture/choices/None/description": "Keine Fixturemethoden", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.en.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.en.json index 9b793a960443..566cada6dbc8 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.en.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.en.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "None", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Enable all extensions shipped by Microsoft (including extensions with a restrictive license)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "Select the fixture kinds to include in the project.", "symbols/Fixture/displayName": "Fixture", "symbols/Fixture/choices/None/description": "No fixture methods", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.es.json index 5e723d58ba8e..ed9bb4c510a4 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.es.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.es.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Ninguno", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Habilitar todas las extensiones enviadas por Microsoft (incluidas las extensiones con una licencia restrictiva)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "Seleccione los tipos de accesorio que desea incluir en el proyecto.", "symbols/Fixture/displayName": "Accesorio", "symbols/Fixture/choices/None/description": "No hay métodos de accesorio", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.fr.json index 242775058935..ae54992c802d 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.fr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.fr.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Aucun", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Activez toutes les extensions fournies par Microsoft (y compris les extensions avec une licence restrictive)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "Sélectionnez les types de fixtures à inclure dans le projet.", "symbols/Fixture/displayName": "Appareil", "symbols/Fixture/choices/None/description": "Aucune méthode de fixture", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.it.json index dc80149574e3..ac162ec9361b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.it.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.it.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Nessuno", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Abilita tutte le estensioni spedite da Microsoft (incluse le estensioni con una licenza restrittiva)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "Selezionare i tipi di fixture da includere nel progetto.", "symbols/Fixture/displayName": "Fixture", "symbols/Fixture/choices/None/description": "Nessun metodo di fixture", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ja.json index c3e72bd47076..3664b666dbb6 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ja.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ja.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "なし", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Microsoft が出荷するすべての拡張機能を有効にする (制限付きライセンスを持つ拡張機能を含む)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "プロジェクトに含めるフィクスチャの種類を選択します。", "symbols/Fixture/displayName": "フィクスチャ", "symbols/Fixture/choices/None/description": "フィクスチャ メソッドがありません", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ko.json index b133708e57d1..cb7207729640 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ko.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ko.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "없음", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Microsoft에서 제공하는 모든 확장 사용(제한 라이선스가 있는 확장 포함)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "프로젝트에 포함할 픽스쳐 종류를 선택합니다.", "symbols/Fixture/displayName": "픽스쳐", "symbols/Fixture/choices/None/description": "픽스쳐 메서드 없음", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pl.json index f680e72320e0..743ab6b9a607 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pl.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pl.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Brak", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Włącz wszystkie rozszerzenia dostarczane przez firmę Microsoft (w tym rozszerzenia z restrykcyjną licencją)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "Wybierz rodzaje warunków początkowych do uwzględnienia w projekcie.", "symbols/Fixture/displayName": "Warunki początkowe", "symbols/Fixture/choices/None/description": "Brak metod początkowych", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pt-BR.json index 4f85ebc17a9b..772b3d0391a7 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.pt-BR.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Nenhum", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Habilitar todas as extensões enviadas pela Microsoft (incluindo extensões com uma licença restritiva)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "Selecione os tipos de acessório a serem incluídos no projeto.", "symbols/Fixture/displayName": "Acessório", "symbols/Fixture/choices/None/description": "Nenhum método de acessório", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ru.json index a3c0ddab5efe..c249542e84a1 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ru.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.ru.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Отсутствует", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Включить все расширения, поставляемые Майкрософт (включая расширения с ограничительной лицензией)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "Выберите типы средств, которые необходимо включить в проект.", "symbols/Fixture/displayName": "Средство", "symbols/Fixture/choices/None/description": "Нет методов работы со средствами", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.tr.json index 8b5c1f3a545b..3ac874bdbf5d 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.tr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.tr.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Hiçbiri", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Microsoft'un gönderdiği tüm uzantıları etkinleştir (kısıtlayıcı lisansı olan uzantılar dahil)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "Projeye dahil edilecek düzen türlerini seçin.", "symbols/Fixture/displayName": "Düzen", "symbols/Fixture/choices/None/description": "Düzen yöntemi yok", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hans.json index ee7d51083668..306a545c8106 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "无", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "启用 Microsoft 提供的所有扩展(包括具有限制性许可证的扩展)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "选择要包含在项目中的固定例程类型。", "symbols/Fixture/displayName": "固定例程", "symbols/Fixture/choices/None/description": "无固定例程方法", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hant.json index 595374d78e9e..07e8dfbae321 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "無", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "啟用由 Microsoft 提供的所有延伸模組 (包括具有有限制授權的延伸模組)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.fs file", "symbols/Fixture/description": "選取要併入專案中的固件類型。", "symbols/Fixture/displayName": "固件", "symbols/Fixture/choices/None/description": "沒有固件方法", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/template.json index 6acfb38af542..c5701db04626 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/.template.config/template.json @@ -97,7 +97,7 @@ "type": "parameter", "datatype": "text", "description": "Sets the LangVersion property in the created project file", - "defaultValue": "latest", + "defaultValue": "", "replaces": "$(ProjectLanguageVersion)", "displayName": "Language version" }, @@ -169,6 +169,13 @@ } ] }, + "ExplicitProgramFile": { + "type": "parameter", + "datatype": "bool", + "description": "When using Microsoft.Testing.Platform, generate an explicit Program.fs file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "displayName": "Use explicit Program.fs file", + "defaultValue": "false" + }, "Fixture": { "type": "parameter", "datatype": "choice", @@ -210,6 +217,16 @@ ] } }, + "sources": [ + { + "modifiers": [ + { + "condition": "(!ExplicitProgramFile || TestRunner != \"Microsoft.Testing.Platform\")", + "exclude": [ "Program.fs" ] + } + ] + } + ], "primaryOutputs": [ { "path": "Company.TestProject1.fsproj" }, { diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/Company.TestProject1.fsproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/Company.TestProject1.fsproj index c259c109e0c9..cd4208fc826e 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/Company.TestProject1.fsproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/Company.TestProject1.fsproj @@ -1,13 +1,11 @@ - + net11.0 TargetFrameworkOverride Company.TestProject1 $(ProjectLanguageVersion) - enable - enable true @@ -19,14 +17,32 @@ $(ExtensionsProfile) + + false + + + + + + + + + + + + + + @@ -36,11 +52,12 @@ TargetFrameworkOverride Company.TestProject1 $(ProjectLanguageVersion) - enable - enable true Exe + + false + @@ -48,17 +65,28 @@ - - - - - + + + + + + + + + + + + + + diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/Program.fs b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/Program.fs new file mode 100644 index 000000000000..6eccbb0871d8 --- /dev/null +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-FSharp/Program.fs @@ -0,0 +1,16 @@ +namespace Company.TestProject1 + +open Microsoft.Testing.Platform.Builder + +module Program = + + [] + let main args = + task { + let! builder = TestApplication.CreateBuilderAsync(args) + SelfRegisteredExtensions.AddSelfRegisteredExtensions(builder, args) + use! app = builder.BuildAsync() + return! app.RunAsync() + } + |> Async.AwaitTask + |> Async.RunSynchronously diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/dotnetcli.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/dotnetcli.host.json index 8cb77b63f5c4..844fa7e089ed 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/dotnetcli.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/dotnetcli.host.json @@ -29,6 +29,10 @@ "shortName": "", "longName": "extensions-profile" }, + "ExplicitProgramFile": { + "shortName": "", + "longName": "explicit-program-file" + }, "Fixture" : { "shortName": "", "longName": "fixture" diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/ide.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/ide.host.json index bdd89182698f..7de07642399e 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/ide.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/ide.host.json @@ -16,6 +16,11 @@ "id": "ExtensionsProfile", "isVisible": true }, + { + "id": "ExplicitProgramFile", + "isVisible": true, + "persistenceScope": "shared" + }, { "id": "CoverageTool", "isVisible": true, diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.cs.json index e1c68bd08bfb..9c1b8dbf5c14 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.cs.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.cs.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Žádné", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Povolit všechna rozšíření odeslaná Microsoftem (včetně rozšíření s omezující licencí)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "Vyberte typy testovacích součástí, které se mají zahrnout do projektu.", "symbols/Fixture/displayName": "Testovací přípravek", "symbols/Fixture/choices/None/description": "Žádné metody testovacího přípravku", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.de.json index fa365fe53277..1dc45c0ab193 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.de.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.de.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Keine", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Alle von Microsoft gelieferten Erweiterungen aktivieren (einschließlich Erweiterungen mit einer restriktiven Lizenz)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "Wählen Sie die Fixturearten aus, die in das Projekt eingeschlossen werden sollen.", "symbols/Fixture/displayName": "Fixture", "symbols/Fixture/choices/None/description": "Keine Fixturemethoden", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.en.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.en.json index 54f70c437b77..df1963f7b7e7 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.en.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.en.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "None", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Enable all extensions shipped by Microsoft (including extensions with a restrictive license)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "Select the fixture kinds to include in the project.", "symbols/Fixture/displayName": "Fixture", "symbols/Fixture/choices/None/description": "No fixture methods", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.es.json index 3cfc950bab1f..e0ba1409ae94 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.es.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.es.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Ninguno", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Habilitar todas las extensiones enviadas por Microsoft (incluidas las extensiones con una licencia restrictiva)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "Seleccione los tipos de accesorio que desea incluir en el proyecto.", "symbols/Fixture/displayName": "Accesorio", "symbols/Fixture/choices/None/description": "No hay métodos de accesorio", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.fr.json index 7d72fc861b42..15209b9d2405 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.fr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.fr.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Aucun", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Activez toutes les extensions fournies par Microsoft (y compris les extensions avec une licence restrictive)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "Sélectionnez les types de fixtures à inclure dans le projet.", "symbols/Fixture/displayName": "Appareil", "symbols/Fixture/choices/None/description": "Aucune méthode de fixture", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.it.json index 9677695ffa5f..0bd67e84402b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.it.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.it.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Nessuno", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Abilita tutte le estensioni spedite da Microsoft (incluse le estensioni con una licenza restrittiva)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "Selezionare i tipi di fixture da includere nel progetto.", "symbols/Fixture/displayName": "Fixture", "symbols/Fixture/choices/None/description": "Nessun metodo di fixture", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ja.json index 34b7a8b0a9f8..c2fbdd2b7c0a 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ja.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ja.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "なし", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Microsoft が出荷するすべての拡張機能を有効にする (制限付きライセンスを持つ拡張機能を含む)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "プロジェクトに含めるフィクスチャの種類を選択します。", "symbols/Fixture/displayName": "フィクスチャ", "symbols/Fixture/choices/None/description": "フィクスチャ メソッドがありません", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ko.json index 5d8df24ba458..914f5827cd73 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ko.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ko.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "없음", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Microsoft에서 제공하는 모든 확장 사용(제한 라이선스가 있는 확장 포함)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "프로젝트에 포함할 픽스쳐 종류를 선택합니다.", "symbols/Fixture/displayName": "픽스쳐", "symbols/Fixture/choices/None/description": "픽스쳐 메서드 없음", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pl.json index 67c99c25dfaa..c500a7b36f6f 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pl.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pl.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Brak", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Włącz wszystkie rozszerzenia dostarczane przez firmę Microsoft (w tym rozszerzenia z restrykcyjną licencją)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "Wybierz rodzaje warunków początkowych do uwzględnienia w projekcie.", "symbols/Fixture/displayName": "Warunki początkowe", "symbols/Fixture/choices/None/description": "Brak metod początkowych", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pt-BR.json index 93e1e5a1b03a..baf5d78b0d8e 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pt-BR.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.pt-BR.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Nenhum", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Habilitar todas as extensões enviadas pela Microsoft (incluindo extensões com uma licença restritiva)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "Selecione os tipos de acessório a serem incluídos no projeto.", "symbols/Fixture/displayName": "Acessório", "symbols/Fixture/choices/None/description": "Nenhum método de acessório", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ru.json index c9ca0f8fcbc3..ebbcebe31e1d 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ru.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.ru.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Отсутствует", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Включить все расширения, поставляемые Майкрософт (включая расширения с ограничительной лицензией)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "Выберите типы средств, которые необходимо включить в проект.", "symbols/Fixture/displayName": "Средство", "symbols/Fixture/choices/None/description": "Нет методов работы со средствами", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.tr.json index f545af8d9829..44ed0f462933 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.tr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.tr.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "Hiçbiri", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "Microsoft'un gönderdiği tüm uzantıları etkinleştir (kısıtlayıcı lisansı olan uzantılar dahil)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "Projeye dahil edilecek düzen türlerini seçin.", "symbols/Fixture/displayName": "Düzen", "symbols/Fixture/choices/None/description": "Düzen yöntemi yok", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json index 9f34cf98c1d0..560a9ca95a4d 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "无", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "启用 Microsoft 提供的所有扩展(包括具有限制性许可证的扩展)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "选择要包含在项目中的固定例程类型。", "symbols/Fixture/displayName": "固定例程", "symbols/Fixture/choices/None/description": "无固定例程方法", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json index 42d7e027ff59..858da7dd8271 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json @@ -40,6 +40,8 @@ "symbols/ExtensionsProfile/choices/None/displayName": "無", "symbols/ExtensionsProfile/choices/AllMicrosoft/description": "啟用由 Microsoft 提供的所有延伸模組 (包括具有有限制授權的延伸模組)", "symbols/ExtensionsProfile/choices/AllMicrosoft/displayName": "AllMicrosoft", + "symbols/ExplicitProgramFile/description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "symbols/ExplicitProgramFile/displayName": "Use explicit Program.vb file", "symbols/Fixture/description": "選取要併入專案中的固件類型。", "symbols/Fixture/displayName": "固件", "symbols/Fixture/choices/None/description": "沒有固件方法", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/template.json index d73954f97e2a..243aa5a42b63 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/.template.config/template.json @@ -97,7 +97,7 @@ "type": "parameter", "datatype": "text", "description": "Sets the LangVersion property in the created project file", - "defaultValue": "latest", + "defaultValue": "", "replaces": "$(ProjectLanguageVersion)", "displayName": "Language version" }, @@ -169,6 +169,13 @@ } ] }, + "ExplicitProgramFile": { + "type": "parameter", + "datatype": "bool", + "description": "When using Microsoft.Testing.Platform, generate an explicit Program.vb file with the test application entry point instead of relying on the entry point auto-generated by the SDK. Has no effect when TestRunner is VSTest.", + "displayName": "Use explicit Program.vb file", + "defaultValue": "false" + }, "Fixture": { "type": "parameter", "datatype": "choice", @@ -210,6 +217,16 @@ ] } }, + "sources": [ + { + "modifiers": [ + { + "condition": "(!ExplicitProgramFile || TestRunner != \"Microsoft.Testing.Platform\")", + "exclude": [ "Program.vb" ] + } + ] + } + ], "primaryOutputs": [ { "path": "Company.TestProject1.vbproj" }, { diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj index 9fd33170462b..d756cb7b9e0c 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/Company.TestProject1.vbproj @@ -1,13 +1,11 @@  - + net11.0 TargetFrameworkOverride Company.TestProject1 $(ProjectLanguageVersion) - enable - enable true @@ -19,6 +17,9 @@ $(ExtensionsProfile) + + false + @@ -31,11 +32,12 @@ TargetFrameworkOverride Company.TestProject1 $(ProjectLanguageVersion) - enable - enable true Exe + + false + @@ -43,11 +45,7 @@ - - - - - + diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/Program.vb b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/Program.vb new file mode 100644 index 000000000000..3a4983c15f7c --- /dev/null +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/MSTest-VisualBasic/Program.vb @@ -0,0 +1,15 @@ +Module Program + + Function Main(args As String()) As Integer + Return MainAsync(args).GetAwaiter().GetResult() + End Function + + Public Async Function MainAsync(args As String()) As Global.System.Threading.Tasks.Task(Of Integer) + Dim builder = Await Global.Microsoft.Testing.Platform.Builder.TestApplication.CreateBuilderAsync(args) + SelfRegisteredExtensions.AddSelfRegisteredExtensions(builder, args) + Using app = Await builder.BuildAsync() + Return Await app.RunAsync() + End Using + End Function + +End Module diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/dotnetcli.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/dotnetcli.host.json index 49fa37c2bf26..a5dff27b9a52 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/dotnetcli.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/dotnetcli.host.json @@ -13,6 +13,10 @@ "shortName": "p", "longName": "enable-pack" }, + "TestRunner": { + "shortName": "", + "longName": "test-runner" + }, "skipRestore": { "longName": "no-restore", "shortName": "" diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/ide.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/ide.host.json index ef689320bee2..5c7595f53521 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/ide.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/ide.host.json @@ -1,6 +1,13 @@ { "$schema": "https://json.schemastore.org/ide.host", "icon": "ide/icon.ico", + "symbolInfo": [ + { + "id": "TestRunner", + "isVisible": true, + "persistenceScope": "shared" + } + ], "tags": [ { "type": "platform", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.cs.json index d301c60c2338..464feb8adefc 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.cs.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.cs.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Cíl net11.0", "symbols/EnablePack/description": "Určuje, jestli se má pro projekt povolit balení (přes „dotnet pack“).", "symbols/EnablePack/displayName": "Povolit balíček", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Je-li zadáno, přeskočí automatické obnovení projektu při vytvoření.", "symbols/skipRestore/displayName": "Přeskočit obnovení", "symbols/langVersion/description": "Nastaví vlastnost LangVersion ve vytvořeném souboru projektu.", "symbols/langVersion/displayName": "Verze jazyka", "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/openInEditor/description": "Otevře UnitTest1.cs v editoru." } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.de.json index 4d51383a70a9..ffef706f3b6d 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.de.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.de.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Ziel.-net11.0", "symbols/EnablePack/description": "Gibt an, ob die Paketerstellung (über \"dotnet pack\") für das Projekt aktiviert werden soll.", "symbols/EnablePack/displayName": "Paket aktivieren", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Wenn angegeben, wird die automatische Wiederherstellung des Projekts beim Erstellen übersprungen.", "symbols/skipRestore/displayName": "Wiederherstellung überspringen", "symbols/langVersion/description": "Legt die Eigenschaft „langVersion“ in der erstellten Projektdatei fest", "symbols/langVersion/displayName": "Sprachversion", "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/openInEditor/description": "Öffnet UnitTest1.cs im Editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.en.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.en.json index 1168a6514753..bbd9aa3aa6b8 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.en.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.en.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Target net11.0", "symbols/EnablePack/description": "Whether or not to enable packaging (via \"dotnet pack\") for the project.", "symbols/EnablePack/displayName": "Enable pack", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/skipRestore/displayName": "Skip restore", "symbols/langVersion/description": "Sets the LangVersion property in the created project file", "symbols/langVersion/displayName": "Language version", "postActions/restoreNugetPackages/description": "Restore NuGet packages required by this project.", "postActions/restoreNugetPackages/manualInstructions/default/text": "Run '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/openInEditor/description": "Opens UnitTest1.cs in the editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.es.json index e45839401a5a..78126d1775a8 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.es.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.es.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Destino net11.0", "symbols/EnablePack/description": "Indica si se va a habilitar o no el empaquetado (a través de \"dotnet pack\") para el proyecto.", "symbols/EnablePack/displayName": "Habilitar paquete", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Si se especifica, se omite la restauración automática del proyecto durante la creación.", "symbols/skipRestore/displayName": "Omitir restauración", "symbols/langVersion/description": "Establece la propiedad LangVersion en el archivo de proyecto creado.", "symbols/langVersion/displayName": "Versión de lenguaje", "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/openInEditor/description": "Abrir UnitTest1.cs en el editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.fr.json index 1b964fcb9810..abdab68779e2 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.fr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.fr.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "net11.0 cible", "symbols/EnablePack/description": "Indique s’il faut activer ou non la création de packages (via « dotnet pack ») pour le projet.", "symbols/EnablePack/displayName": "Activer le pack", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Si spécifié, ignore la restauration automatique du projet lors de la création.", "symbols/skipRestore/displayName": "Ignorer la restauration", "symbols/langVersion/description": "Définit la propriété LangVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du langage", "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/openInEditor/description": "Ouvre UnitTest1.cs dans l’éditeur" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.it.json index 03ae326d6f6b..155374849231 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.it.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.it.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Destinazione net11.0", "symbols/EnablePack/description": "Indica se abilitare o meno la creazione del pacchetto (tramite \"dotnet pack\") per il progetto.", "symbols/EnablePack/displayName": "Abilita pacchetto", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Se specificato, ignora il ripristino automatico del progetto durante la creazione.", "symbols/skipRestore/displayName": "Salta ripristino", "symbols/langVersion/description": "Imposta la proprietà LangVersion nel file di progetto creato", "symbols/langVersion/displayName": "Versione del linguaggio", "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/openInEditor/description": "Apre UnitTest1.cs nell'editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ja.json index d891f6f06478..a463d50e1b85 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ja.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ja.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "ターゲット net11.0", "symbols/EnablePack/description": "(\"dotnet pack\" を使用して) プロジェクトのパッケージ化を有効にするかどうか。", "symbols/EnablePack/displayName": "パックを有効にする", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "指定した場合、作成時にプロジェクトの自動復元がスキップされます。", "symbols/skipRestore/displayName": "復元のスキップ", "symbols/langVersion/description": "作成されたプロジェクト ファイルで LangVersion プロパティを設定します", "symbols/langVersion/displayName": "言語バージョン", "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/openInEditor/description": "エディターで UnitTest1.cs を開きます" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ko.json index 281d92b295b3..a3bccf51332f 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ko.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ko.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "대상 net11.0", "symbols/EnablePack/description": "프로젝트에 대해 패키징(\"dotnet pack\"을 통해)을 활성화할지 여부", "symbols/EnablePack/displayName": "팩 사용", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "지정된 경우, 프로젝트 생성 시 자동 복원을 건너뜁니다.", "symbols/skipRestore/displayName": "복원 건너뛰기", "symbols/langVersion/description": "만든 프로젝트 파일에 LangVersion 속성을 설정합니다", "symbols/langVersion/displayName": "언어 버전", "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/openInEditor/description": "편집기에서 UnitTest1.cs 열기" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.pl.json index 61e9d814a56c..083144bf3eae 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.pl.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.pl.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Docelowa platforma net11.0", "symbols/EnablePack/description": "Określa, czy włączyć pakowanie (za pośrednictwem „pakietu dotnet”) dla projektu.", "symbols/EnablePack/displayName": "Włącz pakiet", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Jeśli ta opcja jest określona, pomija automatyczne przywracanie projektu podczas tworzenia.", "symbols/skipRestore/displayName": "Pomiń przywracanie", "symbols/langVersion/description": "Ustawia właściwość LangVersion w utworzonym pliku projektu", "symbols/langVersion/displayName": "Wersja języka", "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/openInEditor/description": "Otwiera plik UnitTest1.cs w edytorze" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.pt-BR.json index 019010a90a34..ac4c389cbf38 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "net11.0 de destino", "symbols/EnablePack/description": "Se deseja ou não habilitar o empacotamento (via \"dotnet pack\") para o projeto.", "symbols/EnablePack/displayName": "Habilitar pacote", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Se especificado, ignora a restauração automática do projeto na criação.", "symbols/skipRestore/displayName": "Ignorar restauração", "symbols/langVersion/description": "Define a propriedade LangVersion no arquivo do projeto criado", "symbols/langVersion/displayName": "Versão do idioma", "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/openInEditor/description": "Abre o UnitTest1.cs no editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ru.json index 25f550bda5ac..2579c364d99c 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ru.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.ru.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Целевая платформа .NET 10.0", "symbols/EnablePack/description": "Следует ли включить упаковку (через \"dotnet pack\") для проекта.", "symbols/EnablePack/displayName": "Включить пакет", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Если указано, пропускает автоматическое восстановление проекта при создании.", "symbols/skipRestore/displayName": "Пропустить восстановление", "symbols/langVersion/description": "Задает свойство LangVersion в создаваемом файле проекта.", "symbols/langVersion/displayName": "Версия языка", "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/openInEditor/description": "Открывает UnitTest1.cs в редакторе" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.tr.json index 5f3886cb9e8f..e674a30bfc02 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.tr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.tr.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Hedef net11.0", "symbols/EnablePack/description": "Proje için paketlemeyi etkinleştirip etkinleştirmeme ayarı ( \"dotnet pack\" üzerinden).", "symbols/EnablePack/displayName": "Paketi etkinleştir", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Belirtilmişse, oluşturma anında projenin otomatik geri yüklenmesini atlar.", "symbols/skipRestore/displayName": "Geri yüklemeyi atla", "symbols/langVersion/description": "Oluşturulan proje dosyasında LangVersion özelliğini ayarlar", "symbols/langVersion/displayName": "Dil sürümü", "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/openInEditor/description": "UnitTest1.cs'yi düzenleyicide açar" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.zh-Hans.json index ac76d22dab3a..fc65480e632c 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "目标 net11.0", "symbols/EnablePack/description": "是否(通过 \"dotnet pack\")为项目启用打包。", "symbols/EnablePack/displayName": "启用包", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "如果指定,则在创建时跳过项目的自动还原。", "symbols/skipRestore/displayName": "跳过还原", "symbols/langVersion/description": "在创建的项目文件中设置 LangVersion 属性", "symbols/langVersion/displayName": "语言版本", "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/openInEditor/description": "在编辑器中打开 UnitTest1.cs" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.zh-Hant.json index d317222479fe..dc379e8db9bf 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "目標 net11.0", "symbols/EnablePack/description": "是否要啟用專案的封裝 (透過 \"dotnet pack\")。", "symbols/EnablePack/displayName": "啟用壓縮", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "如果指定,則會在建立時跳過專案的自動還原。", "symbols/skipRestore/displayName": "跳過還原", "symbols/langVersion/description": "設定建立的專案檔中的 LangVersion 屬性", "symbols/langVersion/displayName": "語言版本", "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/openInEditor/description": "在編輯器中開啟 UnitTest1.cs" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/template.json index 6a5c0eb76799..accfdf417e55 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/.template.config/template.json @@ -46,6 +46,24 @@ "description": "Whether or not to enable packaging (via \"dotnet pack\") for the project.", "displayName": "Enable pack" }, + "TestRunner": { + "type": "parameter", + "datatype": "choice", + "enableQuotelessLiterals": true, + "description": "Select the runner/platform.", + "displayName": "Test runner", + "defaultValue": "VSTest", + "choices": [ + { + "choice": "Microsoft.Testing.Platform", + "description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information." + }, + { + "choice": "VSTest", + "description": "Use VSTest platform" + } + ] + }, "HostIdentifier": { "type": "bind", "binding": "host:HostIdentifier" @@ -61,9 +79,47 @@ "type": "parameter", "datatype": "text", "description": "Sets the LangVersion property in the created project file", - "defaultValue": "latest", + "defaultValue": "", "replaces": "$(ProjectLanguageVersion)", "displayName": "Language version" + }, + "csharp9orOlder": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^(ISO-1|ISO-2|[1-7]|[8-9]|[8-9]\\.0|7\\.[0-3])$", + "source": "langVersion" + } + }, + "csharp7orOlder": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^(ISO-1|ISO-2|[1-7]|7\\.[0-3])$", + "source": "langVersion" + } + }, + "csharp10orLater": { + "type": "computed", + "value": "!csharp9orOlder" + }, + "csharp8orLater": { + "type": "computed", + "value": "!csharp7orOlder" + }, + "csharpFeature_ImplicitUsings": { + "type": "computed", + "value": "csharp10orLater == \"true\"" + }, + "csharpFeature_Nullable": { + "type": "computed", + "value": "csharp8orLater == \"true\"" + }, + "csharpFeature_FileScopedNamespaces": { + "type": "computed", + "value": "csharp10orLater == \"true\"" } }, "primaryOutputs": [ @@ -86,6 +142,25 @@ "id": "restoreNugetPackages", "continueOnError": true }, + { + "condition": "(TestRunner == \"Microsoft.Testing.Platform\")", + "description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.", + "manualInstructions": [{ "text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform" }], + "actionId": "695A3659-EB40-4FF5-A6A6-C9C4E629FCB0", + "id": "addJsonProperty", + "args": { + "allowFileCreation": true, + "allowPathCreation": true, + "jsonFileName": "global.json", + "parentPropertyPath": "test", + "newJsonPropertyName": "runner", + "newJsonPropertyValue": "Microsoft.Testing.Platform", + "detectRepositoryRoot": true, + "includeAllDirectoriesInSearch": false, + "includeAllParentDirectoriesInSearch": true + }, + "continueOnError": true + }, { "condition": "(HostIdentifier != \"dotnetcli\" && HostIdentifier != \"dotnetcli-preview\")", "description": "Opens UnitTest1.cs in the editor", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/Company.TestProject1.csproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/Company.TestProject1.csproj index e21c9b22a978..06282b9c068e 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/Company.TestProject1.csproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/Company.TestProject1.csproj @@ -5,22 +5,31 @@ TargetFrameworkOverride Company.TestProject1 $(ProjectLanguageVersion) - enable - enable + enable + enable true false + + true + true + Exe + + - - - + + + + + + diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/UnitTest1.cs b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/UnitTest1.cs index 3ff69886477a..115d591b2b43 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/UnitTest1.cs +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-CSharp/UnitTest1.cs @@ -1,4 +1,9 @@ -namespace Company.TestProject1; +#if (!csharpFeature_ImplicitUsings) +using NUnit.Framework; + +#endif +#if (csharpFeature_FileScopedNamespaces) +namespace Company.TestProject1; public class Tests { @@ -13,3 +18,21 @@ public void Test1() Assert.Pass(); } } +#else +namespace Company.TestProject1 +{ + public class Tests + { + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } + } +} +#endif diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/dotnetcli.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/dotnetcli.host.json index 49fa37c2bf26..a5dff27b9a52 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/dotnetcli.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/dotnetcli.host.json @@ -13,6 +13,10 @@ "shortName": "p", "longName": "enable-pack" }, + "TestRunner": { + "shortName": "", + "longName": "test-runner" + }, "skipRestore": { "longName": "no-restore", "shortName": "" diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/ide.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/ide.host.json index ef689320bee2..5c7595f53521 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/ide.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/ide.host.json @@ -1,6 +1,13 @@ { "$schema": "https://json.schemastore.org/ide.host", "icon": "ide/icon.ico", + "symbolInfo": [ + { + "id": "TestRunner", + "isVisible": true, + "persistenceScope": "shared" + } + ], "tags": [ { "type": "platform", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.cs.json index 46fe90a7042e..6691c5c7bdd6 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.cs.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.cs.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Cíl net11.0", "symbols/EnablePack/description": "Určuje, jestli se má pro projekt povolit balení (přes „dotnet pack“).", "symbols/EnablePack/displayName": "Povolit balíček", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Je-li zadáno, přeskočí automatické obnovení projektu při vytvoření.", "symbols/skipRestore/displayName": "Přeskočit obnovení", "symbols/langVersion/description": "Nastaví vlastnost LangVersion ve vytvořeném souboru projektu.", "symbols/langVersion/displayName": "Verze jazyka", "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/openInEditor/description": "Otevře UnitTest1.fs v editoru." } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.de.json index 422330d96422..93b5c17125c3 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.de.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.de.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Ziel.-net11.0", "symbols/EnablePack/description": "Gibt an, ob die Paketerstellung (über \"dotnet pack\") für das Projekt aktiviert werden soll.", "symbols/EnablePack/displayName": "Paket aktivieren", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Wenn angegeben, wird die automatische Wiederherstellung des Projekts beim Erstellen übersprungen.", "symbols/skipRestore/displayName": "Wiederherstellung überspringen", "symbols/langVersion/description": "Legt die Eigenschaft „langVersion“ in der erstellten Projektdatei fest", "symbols/langVersion/displayName": "Sprachversion", "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/openInEditor/description": "Öffnet UnitTest1.fs im Editor." } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.en.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.en.json index b6469dc4f6d2..872076a24c99 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.en.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.en.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Target net11.0", "symbols/EnablePack/description": "Whether or not to enable packaging (via \"dotnet pack\") for the project.", "symbols/EnablePack/displayName": "Enable pack", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/skipRestore/displayName": "Skip restore", "symbols/langVersion/description": "Sets the LangVersion property in the created project file", "symbols/langVersion/displayName": "Language version", "postActions/restoreNugetPackages/description": "Restore NuGet packages required by this project.", "postActions/restoreNugetPackages/manualInstructions/default/text": "Run '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/openInEditor/description": "Opens UnitTest1.fs in the editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.es.json index db1131fa2825..e8a65c3e1113 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.es.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.es.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Destino net11.0", "symbols/EnablePack/description": "Indica si se va a habilitar o no el empaquetado (a través de \"dotnet pack\") para el proyecto.", "symbols/EnablePack/displayName": "Habilitar paquete", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Si se especifica, se omite la restauración automática del proyecto durante la creación.", "symbols/skipRestore/displayName": "Omitir restauración", "symbols/langVersion/description": "Establece la propiedad LangVersion en el archivo de proyecto creado.", "symbols/langVersion/displayName": "Versión de lenguaje", "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/openInEditor/description": "Abrir UnitTest1.fs en el editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.fr.json index fe7f48586378..f2c9701ac063 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.fr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.fr.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "net11.0 cible", "symbols/EnablePack/description": "Indique s’il faut activer ou non la création de packages (via « dotnet pack ») pour le projet.", "symbols/EnablePack/displayName": "Activer le pack", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Si spécifié, ignore la restauration automatique du projet lors de la création.", "symbols/skipRestore/displayName": "Ignorer la restauration", "symbols/langVersion/description": "Définit la propriété LangVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du langage", "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/openInEditor/description": "Ouvre UnitTest1.fs dans l’éditeur" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.it.json index 0655c64bda54..1737471a0366 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.it.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.it.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Destinazione net11.0", "symbols/EnablePack/description": "Indica se abilitare o meno la creazione del pacchetto (tramite \"dotnet pack\") per il progetto.", "symbols/EnablePack/displayName": "Abilita pacchetto", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Se specificato, ignora il ripristino automatico del progetto durante la creazione.", "symbols/skipRestore/displayName": "Salta ripristino", "symbols/langVersion/description": "Imposta la proprietà LangVersion nel file di progetto creato", "symbols/langVersion/displayName": "Versione del linguaggio", "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/openInEditor/description": "Apre UnitTest1.fs nell'editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ja.json index 6596dffa15a7..7a06addbc68f 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ja.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ja.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "ターゲット net11.0", "symbols/EnablePack/description": "(\"dotnet pack\" を使用して) プロジェクトのパッケージ化を有効にするかどうか。", "symbols/EnablePack/displayName": "パックを有効にする", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "指定した場合、作成時にプロジェクトの自動復元がスキップされます。", "symbols/skipRestore/displayName": "復元のスキップ", "symbols/langVersion/description": "作成されたプロジェクト ファイルで LangVersion プロパティを設定します", "symbols/langVersion/displayName": "言語バージョン", "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/openInEditor/description": "エディターで UnitTest1.fs を開きます" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ko.json index b2c20f235da4..db94f9272b16 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ko.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ko.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "대상 net11.0", "symbols/EnablePack/description": "프로젝트에 대해 패키징(\"dotnet pack\"을 통해)을 활성화할지 여부", "symbols/EnablePack/displayName": "팩 사용", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "지정된 경우, 프로젝트 생성 시 자동 복원을 건너뜁니다.", "symbols/skipRestore/displayName": "복원 건너뛰기", "symbols/langVersion/description": "만든 프로젝트 파일에 LangVersion 속성을 설정합니다", "symbols/langVersion/displayName": "언어 버전", "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/openInEditor/description": "편집기에서 UnitTest1.fs 열기" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.pl.json index 436a47e18f7b..2da314cb7c9b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.pl.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.pl.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Docelowa platforma net11.0", "symbols/EnablePack/description": "Określa, czy włączyć pakowanie (za pośrednictwem „pakietu dotnet”) dla projektu.", "symbols/EnablePack/displayName": "Włącz pakiet", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Jeśli ta opcja jest określona, pomija automatyczne przywracanie projektu podczas tworzenia.", "symbols/skipRestore/displayName": "Pomiń przywracanie", "symbols/langVersion/description": "Ustawia właściwość LangVersion w utworzonym pliku projektu", "symbols/langVersion/displayName": "Wersja języka", "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/openInEditor/description": "Otwiera plik UnitTest1.fs w edytorze" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.pt-BR.json index 1f903b642b4f..5b6beeb7d76a 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.pt-BR.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "net11.0 de destino", "symbols/EnablePack/description": "Se deseja ou não habilitar o empacotamento (via \"dotnet pack\") para o projeto.", "symbols/EnablePack/displayName": "Habilitar pacote", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Se especificado, ignora a restauração automática do projeto na criação.", "symbols/skipRestore/displayName": "Ignorar restauração", "symbols/langVersion/description": "Define a propriedade LangVersion no arquivo do projeto criado", "symbols/langVersion/displayName": "Versão do idioma", "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/openInEditor/description": "Abre o UnitTest1.fs no editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ru.json index f905caf725e3..e0843049b9bb 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ru.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.ru.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Целевая платформа .NET 10.0", "symbols/EnablePack/description": "Следует ли включить упаковку (через \"dotnet pack\") для проекта.", "symbols/EnablePack/displayName": "Включить пакет", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Если указано, пропускает автоматическое восстановление проекта при создании.", "symbols/skipRestore/displayName": "Пропустить восстановление", "symbols/langVersion/description": "Задает свойство LangVersion в создаваемом файле проекта.", "symbols/langVersion/displayName": "Версия языка", "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/openInEditor/description": "Открывает UnitTest1.fs в редакторе" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.tr.json index 479512833aa0..e0f7fe15fe17 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.tr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.tr.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Hedef net11.0", "symbols/EnablePack/description": "Proje için paketlemeyi etkinleştirip etkinleştirmeme ayarı ( \"dotnet pack\" üzerinden).", "symbols/EnablePack/displayName": "Paketi etkinleştir", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Belirtilmişse, oluşturma anında projenin otomatik geri yüklenmesini atlar.", "symbols/skipRestore/displayName": "Geri yüklemeyi atla", "symbols/langVersion/description": "Oluşturulan proje dosyasında LangVersion özelliğini ayarlar", "symbols/langVersion/displayName": "Dil sürümü", "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/openInEditor/description": "UnitTest1.fs'yi düzenleyicide açar" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.zh-Hans.json index f63ccf4fbd67..43f4e60a5f08 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "目标 net11.0", "symbols/EnablePack/description": "是否(通过 \"dotnet pack\")为项目启用打包。", "symbols/EnablePack/displayName": "启用包", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "如果指定,则在创建时跳过项目的自动还原。", "symbols/skipRestore/displayName": "跳过还原", "symbols/langVersion/description": "在创建的项目文件中设置 LangVersion 属性", "symbols/langVersion/displayName": "语言版本", "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/openInEditor/description": "在编辑器中打开 UnitTest1.fs" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.zh-Hant.json index 05f63c196e67..dda857ceb533 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "目標 net11.0", "symbols/EnablePack/description": "是否要啟用專案的封裝 (透過 \"dotnet pack\")。", "symbols/EnablePack/displayName": "啟用壓縮", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "如果指定,則會在建立時跳過專案的自動還原。", "symbols/skipRestore/displayName": "跳過還原", "symbols/langVersion/description": "設定建立的專案檔中的 LangVersion 屬性", "symbols/langVersion/displayName": "語言版本", "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/openInEditor/description": "在編輯器中開啟 UnitTest1.fs" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/template.json index f9917f9be27a..8e23a42fc78b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/.template.config/template.json @@ -46,6 +46,24 @@ "description": "Whether or not to enable packaging (via \"dotnet pack\") for the project.", "displayName": "Enable pack" }, + "TestRunner": { + "type": "parameter", + "datatype": "choice", + "enableQuotelessLiterals": true, + "description": "Select the runner/platform.", + "displayName": "Test runner", + "defaultValue": "VSTest", + "choices": [ + { + "choice": "Microsoft.Testing.Platform", + "description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information." + }, + { + "choice": "VSTest", + "description": "Use VSTest platform" + } + ] + }, "HostIdentifier": { "type": "bind", "binding": "host:HostIdentifier" @@ -61,11 +79,21 @@ "type": "parameter", "datatype": "text", "description": "Sets the LangVersion property in the created project file", - "defaultValue": "latest", + "defaultValue": "", "replaces": "$(ProjectLanguageVersion)", "displayName": "Language version" } }, + "sources": [ + { + "modifiers": [ + { + "condition": "(TestRunner == \"Microsoft.Testing.Platform\")", + "exclude": [ "Program.fs" ] + } + ] + } + ], "primaryOutputs": [ { "path": "Company.TestProject1.fsproj" }, { @@ -82,6 +110,25 @@ "id": "restoreNugetPackages", "continueOnError": true }, + { + "condition": "(TestRunner == \"Microsoft.Testing.Platform\")", + "description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.", + "manualInstructions": [{ "text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform" }], + "actionId": "695A3659-EB40-4FF5-A6A6-C9C4E629FCB0", + "id": "addJsonProperty", + "args": { + "allowFileCreation": true, + "allowPathCreation": true, + "jsonFileName": "global.json", + "parentPropertyPath": "test", + "newJsonPropertyName": "runner", + "newJsonPropertyValue": "Microsoft.Testing.Platform", + "detectRepositoryRoot": true, + "includeAllDirectoriesInSearch": false, + "includeAllParentDirectoriesInSearch": true + }, + "continueOnError": true + }, { "condition": "(HostIdentifier != \"dotnetcli\" && HostIdentifier != \"dotnetcli-preview\")", "description": "Opens UnitTest1.fs in the editor", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/Company.TestProject1.fsproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/Company.TestProject1.fsproj index 323e235ae945..732d3dcebe68 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/Company.TestProject1.fsproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/Company.TestProject1.fsproj @@ -8,19 +8,28 @@ true false false + + true + true + Exe + + + + - - - + + + + diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/UnitTest1.fs b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/UnitTest1.fs index 04ad1fc8c27c..7714674e9dd4 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/UnitTest1.fs +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-FSharp/UnitTest1.fs @@ -1,4 +1,8 @@ -module Company.TestProject1 +#if (TestRunner == "Microsoft.Testing.Platform") +module Company.TestProject1.Tests +#else +module Company.TestProject1 +#endif open NUnit.Framework diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/dotnetcli.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/dotnetcli.host.json index 49fa37c2bf26..a5dff27b9a52 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/dotnetcli.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/dotnetcli.host.json @@ -13,6 +13,10 @@ "shortName": "p", "longName": "enable-pack" }, + "TestRunner": { + "shortName": "", + "longName": "test-runner" + }, "skipRestore": { "longName": "no-restore", "shortName": "" diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/ide.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/ide.host.json index ef689320bee2..5c7595f53521 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/ide.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/ide.host.json @@ -1,6 +1,13 @@ { "$schema": "https://json.schemastore.org/ide.host", "icon": "ide/icon.ico", + "symbolInfo": [ + { + "id": "TestRunner", + "isVisible": true, + "persistenceScope": "shared" + } + ], "tags": [ { "type": "platform", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.cs.json index 44333c1eefd2..3a6d86784d38 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.cs.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.cs.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Cíl net11.0", "symbols/EnablePack/description": "Určuje, jestli se má pro projekt povolit balení (přes „dotnet pack“).", "symbols/EnablePack/displayName": "Povolit balíček", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Je-li zadáno, přeskočí automatické obnovení projektu při vytvoření.", "symbols/skipRestore/displayName": "Přeskočit obnovení", "symbols/langVersion/description": "Nastaví vlastnost LangVersion ve vytvořeném souboru projektu.", "symbols/langVersion/displayName": "Verze jazyka", "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/openInEditor/description": "Otevře UnitTest1.vb v editoru." } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.de.json index 3809ff457d24..9d5028e15bb6 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.de.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.de.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Ziel.-net11.0", "symbols/EnablePack/description": "Gibt an, ob die Paketerstellung (über \"dotnet pack\") für das Projekt aktiviert werden soll.", "symbols/EnablePack/displayName": "Paket aktivieren", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Wenn angegeben, wird die automatische Wiederherstellung des Projekts beim Erstellen übersprungen.", "symbols/skipRestore/displayName": "Wiederherstellung überspringen", "symbols/langVersion/description": "Legt die Eigenschaft „langVersion“ in der erstellten Projektdatei fest", "symbols/langVersion/displayName": "Sprachversion", "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/openInEditor/description": "Öffnet UnitTest1.vb im Editor." } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.en.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.en.json index e67aea0ca3d6..2b95ac7fba00 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.en.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.en.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Target net11.0", "symbols/EnablePack/description": "Whether or not to enable packaging (via \"dotnet pack\") for the project.", "symbols/EnablePack/displayName": "Enable pack", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/skipRestore/displayName": "Skip restore", "symbols/langVersion/description": "Sets the LangVersion property in the created project file", "symbols/langVersion/displayName": "Language version", "postActions/restoreNugetPackages/description": "Restore NuGet packages required by this project.", "postActions/restoreNugetPackages/manualInstructions/default/text": "Run '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/openInEditor/description": "Opens UnitTest1.vb in the editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.es.json index e964b400bbc0..3c323688a1b0 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.es.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.es.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Destino net11.0", "symbols/EnablePack/description": "Indica si se va a habilitar o no el empaquetado (a través de \"dotnet pack\") para el proyecto.", "symbols/EnablePack/displayName": "Habilitar paquete", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Si se especifica, se omite la restauración automática del proyecto durante la creación.", "symbols/skipRestore/displayName": "Omitir restauración", "symbols/langVersion/description": "Establece la propiedad LangVersion en el archivo de proyecto creado.", "symbols/langVersion/displayName": "Versión de lenguaje", "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/openInEditor/description": "Abrir UnitTest1.vb en el editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.fr.json index bfd3205ecb1a..b216e1b05bb6 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.fr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.fr.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "net11.0 cible", "symbols/EnablePack/description": "Indique s’il faut activer ou non la création de packages (via « dotnet pack ») pour le projet.", "symbols/EnablePack/displayName": "Activer le pack", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Si spécifié, ignore la restauration automatique du projet lors de la création.", "symbols/skipRestore/displayName": "Ignorer la restauration", "symbols/langVersion/description": "Définit la propriété LangVersion dans le fichier projet créé", "symbols/langVersion/displayName": "Version du langage", "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/openInEditor/description": "Ouvre UnitTest1.vb dans l’éditeur" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.it.json index 739e388c64f7..ab31740f3139 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.it.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.it.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Destinazione net11.0", "symbols/EnablePack/description": "Indica se abilitare o meno la creazione del pacchetto (tramite \"dotnet pack\") per il progetto.", "symbols/EnablePack/displayName": "Abilita pacchetto", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Se specificato, ignora il ripristino automatico del progetto durante la creazione.", "symbols/skipRestore/displayName": "Salta ripristino", "symbols/langVersion/description": "Imposta la proprietà LangVersion nel file di progetto creato", "symbols/langVersion/displayName": "Versione del linguaggio", "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/openInEditor/description": "Apre UnitTest1.vb nell'editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ja.json index e6db7b410ab3..363db9e00ddf 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ja.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ja.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "ターゲット net11.0", "symbols/EnablePack/description": "(\"dotnet pack\" を使用して) プロジェクトのパッケージ化を有効にするかどうか。", "symbols/EnablePack/displayName": "パックを有効にする", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "指定した場合、作成時にプロジェクトの自動復元がスキップされます。", "symbols/skipRestore/displayName": "復元のスキップ", "symbols/langVersion/description": "作成されたプロジェクト ファイルで LangVersion プロパティを設定します", "symbols/langVersion/displayName": "言語バージョン", "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/openInEditor/description": "エディターで UnitTest1.vb を開きます" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ko.json index 615065b861ee..1094dbf44a9b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ko.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ko.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "대상 net11.0", "symbols/EnablePack/description": "프로젝트에 대해 패키징(\"dotnet pack\"을 통해)을 활성화할지 여부", "symbols/EnablePack/displayName": "팩 사용", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "지정된 경우, 프로젝트 생성 시 자동 복원을 건너뜁니다.", "symbols/skipRestore/displayName": "복원 건너뛰기", "symbols/langVersion/description": "만든 프로젝트 파일에 LangVersion 속성을 설정합니다", "symbols/langVersion/displayName": "언어 버전", "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/openInEditor/description": "편집기에서 UnitTest1.vb 열기" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.pl.json index 8c063659d9f2..8f7ad8cdfaa3 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.pl.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.pl.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Docelowa platforma net11.0", "symbols/EnablePack/description": "Określa, czy włączyć pakowanie (za pośrednictwem „pakietu dotnet”) dla projektu.", "symbols/EnablePack/displayName": "Włącz pakiet", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Jeśli ta opcja jest określona, pomija automatyczne przywracanie projektu podczas tworzenia.", "symbols/skipRestore/displayName": "Pomiń przywracanie", "symbols/langVersion/description": "Ustawia właściwość LangVersion w utworzonym pliku projektu", "symbols/langVersion/displayName": "Wersja języka", "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/openInEditor/description": "Otwiera plik UnitTest1.vb w edytorze" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.pt-BR.json index 438e8c27b5b7..7a463b7d8d8f 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.pt-BR.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.pt-BR.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "net11.0 de destino", "symbols/EnablePack/description": "Se deseja ou não habilitar o empacotamento (via \"dotnet pack\") para o projeto.", "symbols/EnablePack/displayName": "Habilitar pacote", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Se especificado, ignora a restauração automática do projeto na criação.", "symbols/skipRestore/displayName": "Ignorar restauração", "symbols/langVersion/description": "Define a propriedade LangVersion no arquivo do projeto criado", "symbols/langVersion/displayName": "Versão do idioma", "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/openInEditor/description": "Abre o UnitTest1.vb no editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ru.json index 954666a66adc..34e6f7d55e93 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ru.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.ru.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Целевая платформа .NET 10.0", "symbols/EnablePack/description": "Следует ли включить упаковку (через \"dotnet pack\") для проекта.", "symbols/EnablePack/displayName": "Включить пакет", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Если указано, пропускает автоматическое восстановление проекта при создании.", "symbols/skipRestore/displayName": "Пропустить восстановление", "symbols/langVersion/description": "Задает свойство LangVersion в создаваемом файле проекта.", "symbols/langVersion/displayName": "Версия языка", "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/openInEditor/description": "Открывает UnitTest1.vb в редакторе" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.tr.json index a0bf5d6d4d9a..d4d8c786fe7a 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.tr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.tr.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "Hedef net11.0", "symbols/EnablePack/description": "Proje için paketlemeyi etkinleştirip etkinleştirmeme ayarı ( \"dotnet pack\" üzerinden).", "symbols/EnablePack/displayName": "Paketi etkinleştir", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "Belirtilmişse, oluşturma anında projenin otomatik geri yüklenmesini atlar.", "symbols/skipRestore/displayName": "Geri yüklemeyi atla", "symbols/langVersion/description": "Oluşturulan proje dosyasında LangVersion özelliğini ayarlar", "symbols/langVersion/displayName": "Dil sürümü", "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/openInEditor/description": "UnitTest1.vb'yi düzenleyicide açar" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json index 0ec17172948d..4d8f87a533dd 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "目标 net11.0", "symbols/EnablePack/description": "是否(通过 \"dotnet pack\")为项目启用打包。", "symbols/EnablePack/displayName": "启用包", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "如果指定,则在创建时跳过项目的自动还原。", "symbols/skipRestore/displayName": "跳过还原", "symbols/langVersion/description": "在创建的项目文件中设置 LangVersion 属性", "symbols/langVersion/displayName": "语言版本", "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/openInEditor/description": "在编辑器中打开 UnitTest1.vb" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json index 92c2191a1910..c9a064d10d5a 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json @@ -9,11 +9,17 @@ "symbols/Framework/choices/net11.0/description": "目標 net11.0", "symbols/EnablePack/description": "是否要啟用專案的封裝 (透過 \"dotnet pack\")。", "symbols/EnablePack/displayName": "啟用壓縮", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/skipRestore/description": "如果指定,則會在建立時跳過專案的自動還原。", "symbols/skipRestore/displayName": "跳過還原", "symbols/langVersion/description": "設定建立的專案檔中的 LangVersion 屬性", "symbols/langVersion/displayName": "語言版本", "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/openInEditor/description": "在編輯器中開啟 UnitTest1.vb" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/template.json index 7854e54018f5..329f61712cbb 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/.template.config/template.json @@ -46,6 +46,24 @@ "description": "Whether or not to enable packaging (via \"dotnet pack\") for the project.", "displayName": "Enable pack" }, + "TestRunner": { + "type": "parameter", + "datatype": "choice", + "enableQuotelessLiterals": true, + "description": "Select the runner/platform.", + "displayName": "Test runner", + "defaultValue": "VSTest", + "choices": [ + { + "choice": "Microsoft.Testing.Platform", + "description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information." + }, + { + "choice": "VSTest", + "description": "Use VSTest platform" + } + ] + }, "HostIdentifier": { "type": "bind", "binding": "host:HostIdentifier" @@ -61,7 +79,7 @@ "type": "parameter", "datatype": "text", "description": "Sets the LangVersion property in the created project file", - "defaultValue": "latest", + "defaultValue": "", "replaces": "$(ProjectLanguageVersion)", "displayName": "Language version" } @@ -82,6 +100,25 @@ "id": "restoreNugetPackages", "continueOnError": true }, + { + "condition": "(TestRunner == \"Microsoft.Testing.Platform\")", + "description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.", + "manualInstructions": [{ "text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform" }], + "actionId": "695A3659-EB40-4FF5-A6A6-C9C4E629FCB0", + "id": "addJsonProperty", + "args": { + "allowFileCreation": true, + "allowPathCreation": true, + "jsonFileName": "global.json", + "parentPropertyPath": "test", + "newJsonPropertyName": "runner", + "newJsonPropertyValue": "Microsoft.Testing.Platform", + "detectRepositoryRoot": true, + "includeAllDirectoriesInSearch": false, + "includeAllParentDirectoriesInSearch": true + }, + "continueOnError": true + }, { "condition": "(HostIdentifier != \"dotnetcli\" && HostIdentifier != \"dotnetcli-preview\")", "description": "Opens UnitTest1.vb in the editor", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/Company.TestProject1.vbproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/Company.TestProject1.vbproj index 3ac473bc2f43..9d371f3fccfc 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/Company.TestProject1.vbproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/NUnit-VisualBasic/Company.TestProject1.vbproj @@ -7,14 +7,21 @@ $(ProjectLanguageVersion) true false + + true + true + Exe + + - - - + + + + diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/.template.config/template.json index 339026195198..5757f0eb5779 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/.template.config/template.json @@ -117,10 +117,57 @@ "type": "parameter", "datatype": "text", "description": "Sets the LangVersion property in the created project file", - "defaultValue": "latest", + "defaultValue": "", "replaces": "$(ProjectLanguageVersion)", "displayName": "Language version" }, + "netFramework": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^net4\\d", + "source": "Framework" + } + }, + "csharp9orOlder": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^(ISO-1|ISO-2|[1-7]|[8-9]|[8-9]\\.0|7\\.[0-3])$", + "source": "langVersion" + } + }, + "csharp7orOlder": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^(ISO-1|ISO-2|[1-7]|7\\.[0-3])$", + "source": "langVersion" + } + }, + "csharp10orLater": { + "type": "computed", + "value": "!csharp9orOlder" + }, + "csharp8orLater": { + "type": "computed", + "value": "!csharp7orOlder" + }, + "csharpFeature_ImplicitUsings": { + "type": "computed", + "value": "(netFramework != \"true\" || langVersion != \"\") && csharp10orLater == \"true\"" + }, + "csharpFeature_Nullable": { + "type": "computed", + "value": "(netFramework != \"true\" || langVersion != \"\") && csharp8orLater == \"true\"" + }, + "csharpFeature_FileScopedNamespaces": { + "type": "computed", + "value": "(netFramework != \"true\" || langVersion != \"\") && csharp10orLater == \"true\"" + }, "UseMSTestSdk": { "type": "parameter", "datatype": "bool", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj index 6c02220c16fd..4bce00147736 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/Company.TestProject1.csproj @@ -1,13 +1,13 @@  - + net11.0 TargetFrameworkOverride Company.TestProject1 $(ProjectLanguageVersion) - enable - enable + enable + enable true true @@ -32,8 +32,8 @@ TargetFrameworkOverride Company.TestProject1 $(ProjectLanguageVersion) - enable - enable + enable + enable true Exe @@ -45,15 +45,17 @@ - + + + diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/MSTestSettings.cs b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/MSTestSettings.cs index aaf278c844f0..ed04ed055494 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/MSTestSettings.cs +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/MSTestSettings.cs @@ -1 +1,5 @@ -[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] +#if (!csharpFeature_ImplicitUsings) +using Microsoft.VisualStudio.TestTools.UnitTesting; + +#endif +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/Test1.cs b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/Test1.cs index b3e8e48318c0..a3f7665a4ee6 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/Test1.cs +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-MSTest-CSharp/Test1.cs @@ -1,4 +1,12 @@ -namespace Company.TestProject1; +#if (!csharpFeature_ImplicitUsings) +using Microsoft.Playwright.MSTest; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +#endif +#if (csharpFeature_FileScopedNamespaces) +namespace Company.TestProject1; [TestClass] public class Test1 : PageTest @@ -72,3 +80,80 @@ public async Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingToTheIntro await Expect(Page).ToHaveURLAsync(new Regex(".*intro")); } } +#else +namespace Company.TestProject1 +{ + [TestClass] + public class Test1 : PageTest + { +#if (Fixture == AssemblyInitialize) + [AssemblyInitialize] + public static void AssemblyInit(TestContext context) + { + // This method is called once for the test assembly, before any tests are run. + } + +#endif +#if (Fixture == AssemblyCleanup) + [AssemblyCleanup] + public static void AssemblyCleanup() + { + // This method is called once for the test assembly, after all tests are run. + } + +#endif +#if (Fixture == ClassInitialize) + [ClassInitialize] + public static void ClassInit(TestContext context) + { + // This method is called once for the test class, before any tests of the class are run. + } + +#endif +#if (Fixture == ClassCleanup) + [ClassCleanup] + public static void ClassCleanup() + { + // This method is called once for the test class, after all tests of the class are run. + } + +#endif +#if (Fixture == TestInitialize) + [TestInitialize] + public void TestInit() + { + // This method is called before each test method. + } + +#endif +#if (Fixture == TestCleanup) + [TestCleanup] + public void TestCleanup() + { + // This method is called after each test method. + } + +#endif + [TestMethod] + public async Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingToTheIntroPage() + { + await Page.GotoAsync("https://playwright.dev"); + + // Expect a title "to contain" a substring. + await Expect(Page).ToHaveTitleAsync(new Regex("Playwright")); + + // create a locator + var getStarted = Page.Locator("text=Get Started"); + + // Expect an attribute "to be strictly equal" to the value. + await Expect(getStarted).ToHaveAttributeAsync("href", "/docs/intro"); + + // Click the get started link. + await getStarted.ClickAsync(); + + // Expects the URL to contain intro. + await Expect(Page).ToHaveURLAsync(new Regex(".*intro")); + } + } +} +#endif diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/.template.config/template.json index 38ddb706b7cb..f930a2ad02c2 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/.template.config/template.json @@ -60,9 +60,47 @@ "type": "parameter", "datatype": "text", "description": "Sets the LangVersion property in the created project file", - "defaultValue": "latest", + "defaultValue": "", "replaces": "$(ProjectLanguageVersion)", "displayName": "Language version" + }, + "csharp9orOlder": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^(ISO-1|ISO-2|[1-7]|[8-9]|[8-9]\\.0|7\\.[0-3])$", + "source": "langVersion" + } + }, + "csharp7orOlder": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^(ISO-1|ISO-2|[1-7]|7\\.[0-3])$", + "source": "langVersion" + } + }, + "csharp10orLater": { + "type": "computed", + "value": "!csharp9orOlder" + }, + "csharp8orLater": { + "type": "computed", + "value": "!csharp7orOlder" + }, + "csharpFeature_ImplicitUsings": { + "type": "computed", + "value": "csharp10orLater == \"true\"" + }, + "csharpFeature_Nullable": { + "type": "computed", + "value": "csharp8orLater == \"true\"" + }, + "csharpFeature_FileScopedNamespaces": { + "type": "computed", + "value": "csharp10orLater == \"true\"" } }, "primaryOutputs": [ diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/Company.TestProject1.csproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/Company.TestProject1.csproj index 12312d733513..773434ebb4e8 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/Company.TestProject1.csproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/Company.TestProject1.csproj @@ -5,8 +5,8 @@ TargetFrameworkOverride Company.TestProject1 $(ProjectLanguageVersion) - enable - enable + enable + enable true false @@ -15,16 +15,18 @@ - - - + + + + + diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/UnitTest1.cs b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/UnitTest1.cs index 6f683a9651c3..b7c7b6bfd3a2 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/UnitTest1.cs +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/Playwright-NUnit-CSharp/UnitTest1.cs @@ -1,4 +1,12 @@ -namespace Company.TestProject1; +#if (!csharpFeature_ImplicitUsings) +using Microsoft.Playwright.NUnit; +using NUnit.Framework; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +#endif +#if (csharpFeature_FileScopedNamespaces) +namespace Company.TestProject1; [Parallelizable(ParallelScope.Self)] [TestFixture] @@ -25,3 +33,33 @@ public async Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingtoTheIntro await Expect(Page).ToHaveURLAsync(new Regex(".*intro")); } } +#else +namespace Company.TestProject1 +{ + [Parallelizable(ParallelScope.Self)] + [TestFixture] + public class Tests : PageTest + { + [Test] + public async Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingtoTheIntroPage() + { + await Page.GotoAsync("https://playwright.dev"); + + // Expect a title "to contain" a substring. + await Expect(Page).ToHaveTitleAsync(new Regex("Playwright")); + + // create a locator + var getStarted = Page.Locator("text=Get Started"); + + // Expect an attribute "to be strictly equal" to the value. + await Expect(getStarted).ToHaveAttributeAsync("href", "/docs/intro"); + + // Click the get started link. + await getStarted.ClickAsync(); + + // Expects the URL to contain intro. + await Expect(Page).ToHaveURLAsync(new Regex(".*intro")); + } + } +} +#endif diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/dotnetcli.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/dotnetcli.host.json index 49fa37c2bf26..747f5b2e33b8 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/dotnetcli.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/dotnetcli.host.json @@ -9,6 +9,14 @@ "Framework": { "longName": "framework" }, + "XUnitVersion": { + "shortName": "", + "longName": "xunit-version" + }, + "TestRunner": { + "shortName": "", + "longName": "test-runner" + }, "EnablePack": { "shortName": "p", "longName": "enable-pack" diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/ide.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/ide.host.json index ef689320bee2..45902415890b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/ide.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/ide.host.json @@ -1,6 +1,18 @@ { "$schema": "https://json.schemastore.org/ide.host", "icon": "ide/icon.ico", + "symbolInfo": [ + { + "id": "XUnitVersion", + "isVisible": true, + "persistenceScope": "shared" + }, + { + "id": "TestRunner", + "isVisible": true, + "persistenceScope": "shared" + } + ], "tags": [ { "type": "platform", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.cs.json index 1d76e2855e60..485019a066fa 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.cs.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.cs.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "Cílová architektura pro projekt", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Určuje, jestli se má pro projekt povolit balení (přes „dotnet pack“).", "symbols/EnablePack/displayName": "Povolit balíček", "symbols/skipRestore/description": "Je-li zadáno, přeskočí automatické obnovení projektu při vytvoření.", "symbols/skipRestore/displayName": "Přeskočit obnovení", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "Otevře Class1.cs v editoru." } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.de.json index 9101e4d19017..aabcd0ddf04e 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.de.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.de.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "Das Zielframework für das Projekt.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Ziel.-net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Gibt an, ob die Paketerstellung (über \"dotnet pack\") für das Projekt aktiviert werden soll.", "symbols/EnablePack/displayName": "Paket aktivieren", "symbols/skipRestore/description": "Wenn angegeben, wird die automatische Wiederherstellung des Projekts beim Erstellen übersprungen.", "symbols/skipRestore/displayName": "Wiederherstellung überspringen", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "Öffnet Class1.cs“ im Editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.en.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.en.json index 0003f3eb62e4..2df8b46d581f 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.en.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.en.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Target net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Whether or not to enable packaging (via \"dotnet pack\") for the project.", "symbols/EnablePack/displayName": "Enable pack", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/skipRestore/displayName": "Skip restore", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "postActions/restoreNugetPackages/description": "Restore NuGet packages required by this project.", "postActions/restoreNugetPackages/manualInstructions/default/text": "Run '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/openInEditor/description": "Opens Class1.cs in the editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.es.json index 4ea2cb87597a..a9b645e63421 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.es.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.es.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "Marco de destino del proyecto.", "symbols/Framework/displayName": "Plataforma", "symbols/Framework/choices/net11.0/description": "Destino net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Indica si se va a habilitar o no el empaquetado (a través de \"dotnet pack\") para el proyecto.", "symbols/EnablePack/displayName": "Habilitar paquete", "symbols/skipRestore/description": "Si se especifica, se omite la restauración automática del proyecto durante la creación.", "symbols/skipRestore/displayName": "Omitir restauración", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "Abrir Class1.cs en el editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.fr.json index b1c52236a21a..a3026fa7d166 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.fr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.fr.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "Le cadre cible du projet.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "net11.0 cible", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Indique s’il faut activer ou non la création de packages (via « dotnet pack ») pour le projet.", "symbols/EnablePack/displayName": "Activer le pack", "symbols/skipRestore/description": "Si spécifié, ignore la restauration automatique du projet lors de la création.", "symbols/skipRestore/displayName": "Ignorer la restauration", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "Ouvre Class1.cs dans l’éditeur" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.it.json index c9717f8ebe69..12dcff26763f 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.it.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.it.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "Il framework di destinazione per il progetto.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Destinazione net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Indica se abilitare o meno la creazione del pacchetto (tramite \"dotnet pack\") per il progetto.", "symbols/EnablePack/displayName": "Abilita pacchetto", "symbols/skipRestore/description": "Se specificato, ignora il ripristino automatico del progetto durante la creazione.", "symbols/skipRestore/displayName": "Salta ripristino", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "Apre Class1.cs nell'editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ja.json index 5d1935afaa41..8297efa48100 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ja.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ja.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "プロジェクトのターゲット フレームワークです。", "symbols/Framework/displayName": "フレームワーク", "symbols/Framework/choices/net11.0/description": "ターゲット net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "(\"dotnet pack\" を使用して) プロジェクトのパッケージ化を有効にするかどうか。", "symbols/EnablePack/displayName": "パックを有効にする", "symbols/skipRestore/description": "指定した場合、作成時にプロジェクトの自動復元がスキップされます。", "symbols/skipRestore/displayName": "復元のスキップ", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "エディターで Class1.cs を開きます" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ko.json index 4f43081b779b..ca3935cc76d6 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ko.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ko.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "프로젝트에 대한 대상 프레임워크입니다.", "symbols/Framework/displayName": "프레임워크", "symbols/Framework/choices/net11.0/description": "대상 net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "프로젝트에 대해 패키징(\"dotnet pack\"을 통해)을 활성화할지 여부", "symbols/EnablePack/displayName": "팩 사용", "symbols/skipRestore/description": "지정된 경우, 프로젝트 생성 시 자동 복원을 건너뜁니다.", "symbols/skipRestore/displayName": "복원 건너뛰기", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "편집기에서 Class1.cs 열기" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.pl.json index 9859cc61cea9..c6762e7b71dd 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.pl.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.pl.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "Platforma docelowa dla tego projektu.", "symbols/Framework/displayName": "Struktura", "symbols/Framework/choices/net11.0/description": "Docelowa platforma net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Określa, czy włączyć pakowanie (za pośrednictwem „pakietu dotnet”) dla projektu.", "symbols/EnablePack/displayName": "Włącz pakiet", "symbols/skipRestore/description": "Jeśli ta opcja jest określona, pomija automatyczne przywracanie projektu podczas tworzenia.", "symbols/skipRestore/displayName": "Pomiń przywracanie", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "Otwiera plik Class1.cs w edytorze" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.pt-BR.json index b29d142212bd..72e59fd12610 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "A estrutura de destino para o projeto.", "symbols/Framework/displayName": "Estrutura", "symbols/Framework/choices/net11.0/description": "net11.0 de destino", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Se deseja ou não habilitar o empacotamento (via \"dotnet pack\") para o projeto.", "symbols/EnablePack/displayName": "Habilitar pacote", "symbols/skipRestore/description": "Se especificado, ignora a restauração automática do projeto na criação.", "symbols/skipRestore/displayName": "Ignorar restauração", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "Abrir Class1.cs no editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ru.json index fe1d650e21a7..7e3f924b9947 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ru.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.ru.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "Целевая платформа для проекта.", "symbols/Framework/displayName": "Платформа", "symbols/Framework/choices/net11.0/description": "Целевая платформа .NET 10.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Следует ли включить упаковку (через \"dotnet pack\") для проекта.", "symbols/EnablePack/displayName": "Включить пакет", "symbols/skipRestore/description": "Если указано, пропускает автоматическое восстановление проекта при создании.", "symbols/skipRestore/displayName": "Пропустить восстановление", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "Открывает файл Class1.cs в редакторе" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.tr.json index c91a8e762889..c690b023d85c 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.tr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.tr.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "Projenin hedef çerçevesi.", "symbols/Framework/displayName": "Çerçeve", "symbols/Framework/choices/net11.0/description": "Hedef net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Proje için paketlemeyi etkinleştirip etkinleştirmeme ayarı ( \"dotnet pack\" üzerinden).", "symbols/EnablePack/displayName": "Paketi etkinleştir", "symbols/skipRestore/description": "Belirtilmişse, oluşturma anında projenin otomatik geri yüklenmesini atlar.", "symbols/skipRestore/displayName": "Geri yüklemeyi atla", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "Düzenleyicide Class1.cs dosyasını açar" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.zh-Hans.json index e5908ba38368..73f07c82c64b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "项目的目标框架。", "symbols/Framework/displayName": "框架", "symbols/Framework/choices/net11.0/description": "目标 net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "是否(通过 \"dotnet pack\")为项目启用打包。", "symbols/EnablePack/displayName": "启用包", "symbols/skipRestore/description": "如果指定,则在创建时跳过项目的自动还原。", "symbols/skipRestore/displayName": "跳过还原", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "在编辑器中打开 Class1.cs" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 84b2a3b73a18..31adbbf54273 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -7,11 +7,23 @@ "symbols/Framework/description": "專案的目標架構。", "symbols/Framework/displayName": "架構", "symbols/Framework/choices/net11.0/description": "目標 net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "是否要啟用專案的封裝 (透過 \"dotnet pack\")。", "symbols/EnablePack/displayName": "啟用壓縮", "symbols/skipRestore/description": "如果指定,則會在建立時跳過專案的自動還原。", "symbols/skipRestore/displayName": "跳過還原", + "symbols/langVersion/description": "Sets the LangVersion property in the created project file", + "symbols/langVersion/displayName": "Language version", "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/openInEditor/description": "在編輯器中開啟 Class1.cs" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/template.json index 899b4e539845..35fb779ee9ff 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/.template.config/template.json @@ -15,6 +15,18 @@ }, "sourceName": "Company.TestProject1", "preferNameDirectory": true, + "sources": [ + { + "modifiers": [ + { + "condition": "(XUnitVersion != \"v3\")", + "exclude": [ + "xunit.runner.json" + ] + } + ] + } + ], "symbols": { "TargetFrameworkOverride": { "type": "parameter", @@ -38,6 +50,43 @@ "replaces": "net11.0", "defaultValue": "net11.0" }, + "XUnitVersion": { + "type": "parameter", + "datatype": "choice", + "enableQuotelessLiterals": true, + "description": "The version of xUnit.net to use.", + "displayName": "xUnit.net version", + "defaultValue": "v2", + "choices": [ + { + "choice": "v2", + "description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility)." + }, + { + "choice": "v3", + "description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information." + } + ] + }, + "TestRunner": { + "type": "parameter", + "datatype": "choice", + "enableQuotelessLiterals": true, + "description": "Select the runner/platform.", + "displayName": "Test runner", + "isEnabled": "(XUnitVersion == v3)", + "defaultValue": "Microsoft.Testing.Platform", + "choices": [ + { + "choice": "Microsoft.Testing.Platform", + "description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information." + }, + { + "choice": "VSTest", + "description": "Use VSTest platform" + } + ] + }, "EnablePack": { "type": "parameter", "datatype": "bool", @@ -55,6 +104,52 @@ "description": "If specified, skips the automatic restore of the project on create.", "displayName": "Skip restore", "defaultValue": "false" + }, + "langVersion": { + "type": "parameter", + "datatype": "text", + "description": "Sets the LangVersion property in the created project file", + "defaultValue": "", + "replaces": "$(ProjectLanguageVersion)", + "displayName": "Language version" + }, + "csharp9orOlder": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^(ISO-1|ISO-2|[1-7]|[8-9]|[8-9]\\.0|7\\.[0-3])$", + "source": "langVersion" + } + }, + "csharp7orOlder": { + "type": "generated", + "generator": "regexMatch", + "datatype": "bool", + "parameters": { + "pattern": "^(ISO-1|ISO-2|[1-7]|7\\.[0-3])$", + "source": "langVersion" + } + }, + "csharp10orLater": { + "type": "computed", + "value": "!csharp9orOlder" + }, + "csharp8orLater": { + "type": "computed", + "value": "!csharp7orOlder" + }, + "csharpFeature_ImplicitUsings": { + "type": "computed", + "value": "csharp10orLater == \"true\"" + }, + "csharpFeature_Nullable": { + "type": "computed", + "value": "csharp8orLater == \"true\"" + }, + "csharpFeature_FileScopedNamespaces": { + "type": "computed", + "value": "csharp10orLater == \"true\"" } }, "primaryOutputs": [ @@ -78,6 +173,25 @@ "id": "restoreNugetPackages", "continueOnError": true }, + { + "condition": "(XUnitVersion == \"v3\" && TestRunner == \"Microsoft.Testing.Platform\")", + "description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.", + "manualInstructions": [{ "text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform" }], + "actionId": "695A3659-EB40-4FF5-A6A6-C9C4E629FCB0", + "id": "addJsonProperty", + "args": { + "allowFileCreation": true, + "allowPathCreation": true, + "jsonFileName": "global.json", + "parentPropertyPath": "test", + "newJsonPropertyName": "runner", + "newJsonPropertyValue": "Microsoft.Testing.Platform", + "detectRepositoryRoot": true, + "includeAllDirectoriesInSearch": false, + "includeAllParentDirectoriesInSearch": true + }, + "continueOnError": true + }, { "condition": "(HostIdentifier != \"dotnetcli\" && HostIdentifier != \"dotnetcli-preview\")", "description": "Opens Class1.cs in the editor", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/Company.TestProject1.csproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/Company.TestProject1.csproj index 5fa6752c3c29..a38a98df9136 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/Company.TestProject1.csproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/Company.TestProject1.csproj @@ -4,21 +4,48 @@ net11.0 TargetFrameworkOverride Company.TestProject1 - enable - enable + $(ProjectLanguageVersion) + enable + enable true false + + Exe + + + true + + + + + + + + + + + + + + + + + + - + + + + \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/UnitTest1.cs b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/UnitTest1.cs index 7e243fefdc29..2c8060cca1b3 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/UnitTest1.cs +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/UnitTest1.cs @@ -1,10 +1,30 @@ -namespace Company.TestProject1; +#if (!csharpFeature_ImplicitUsings) +using Xunit; + +#endif +#if (csharpFeature_FileScopedNamespaces) +namespace Company.TestProject1; public class UnitTest1 { [Fact] public void Test1() { +#if (XUnitVersion == "v3") + Assert.True(true); +#endif + } +} +#else +namespace Company.TestProject1 +{ + public class UnitTest1 + { + [Fact] + public void Test1() + { + } } } +#endif diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/xunit.runner.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/xunit.runner.json new file mode 100644 index 000000000000..3e04e18aa4e1 --- /dev/null +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-CSharp/xunit.runner.json @@ -0,0 +1,3 @@ +{ + "$schema": "https://xunit.net/schema/v3.1/xunit.runner.schema.json" +} diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/dotnetcli.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/dotnetcli.host.json index 49fa37c2bf26..747f5b2e33b8 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/dotnetcli.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/dotnetcli.host.json @@ -9,6 +9,14 @@ "Framework": { "longName": "framework" }, + "XUnitVersion": { + "shortName": "", + "longName": "xunit-version" + }, + "TestRunner": { + "shortName": "", + "longName": "test-runner" + }, "EnablePack": { "shortName": "p", "longName": "enable-pack" diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/ide.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/ide.host.json index ef689320bee2..45902415890b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/ide.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/ide.host.json @@ -1,6 +1,18 @@ { "$schema": "https://json.schemastore.org/ide.host", "icon": "ide/icon.ico", + "symbolInfo": [ + { + "id": "XUnitVersion", + "isVisible": true, + "persistenceScope": "shared" + }, + { + "id": "TestRunner", + "isVisible": true, + "persistenceScope": "shared" + } + ], "tags": [ { "type": "platform", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.cs.json index 0fc9ad102eab..ba1adfab57c6 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.cs.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.cs.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Cílová architektura pro projekt", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Určuje, jestli se má pro projekt povolit balení (přes „dotnet pack“).", "symbols/EnablePack/displayName": "Povolit balíček", "symbols/skipRestore/description": "Je-li zadáno, přeskočí automatické obnovení projektu při vytvoření.", "symbols/skipRestore/displayName": "Přeskočit obnovení", "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/openInEditor/description": "Otevře Tests.fs v editoru." } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.de.json index 22a3749eee4e..63967323cfcb 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.de.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.de.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Das Zielframework für das Projekt.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Ziel.-net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Gibt an, ob die Paketerstellung (über \"dotnet pack\") für das Projekt aktiviert werden soll.", "symbols/EnablePack/displayName": "Paket aktivieren", "symbols/skipRestore/description": "Wenn angegeben, wird die automatische Wiederherstellung des Projekts beim Erstellen übersprungen.", "symbols/skipRestore/displayName": "Wiederherstellung überspringen", "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/openInEditor/description": "Öffnet Tests.fs im Editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.en.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.en.json index 72b954b04caa..c91149fe0746 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.en.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.en.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Target net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Whether or not to enable packaging (via \"dotnet pack\") for the project.", "symbols/EnablePack/displayName": "Enable pack", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/skipRestore/displayName": "Skip restore", "postActions/restoreNugetPackages/description": "Restore NuGet packages required by this project.", "postActions/restoreNugetPackages/manualInstructions/default/text": "Run '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/openInEditor/description": "Opens Tests.fs in the editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.es.json index 17ab16f67a19..cfb1e2f868d8 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.es.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.es.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Marco de destino del proyecto.", "symbols/Framework/displayName": "Plataforma", "symbols/Framework/choices/net11.0/description": "Destino net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Indica si se va a habilitar o no el empaquetado (a través de \"dotnet pack\") para el proyecto.", "symbols/EnablePack/displayName": "Habilitar paquete", "symbols/skipRestore/description": "Si se especifica, se omite la restauración automática del proyecto durante la creación.", "symbols/skipRestore/displayName": "Omitir restauración", "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/openInEditor/description": "Abrir Tests.fs en el editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.fr.json index 7a9617557855..5315a1d8f2ef 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.fr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.fr.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Le cadre cible du projet.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "net11.0 cible", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Indique s’il faut activer ou non la création de packages (via « dotnet pack ») pour le projet.", "symbols/EnablePack/displayName": "Activer le pack", "symbols/skipRestore/description": "Si spécifié, ignore la restauration automatique du projet lors de la création.", "symbols/skipRestore/displayName": "Ignorer la restauration", "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/openInEditor/description": "Ouvre Tests.fs dans l’éditeur" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.it.json index 409acc2e6d86..d96f3cd5df41 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.it.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.it.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Il framework di destinazione per il progetto.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Destinazione net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Indica se abilitare o meno la creazione del pacchetto (tramite \"dotnet pack\") per il progetto.", "symbols/EnablePack/displayName": "Abilita pacchetto", "symbols/skipRestore/description": "Se specificato, ignora il ripristino automatico del progetto durante la creazione.", "symbols/skipRestore/displayName": "Salta ripristino", "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/openInEditor/description": "Apre Tests.fs nell'editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ja.json index 04d298e4a98a..4131b6062909 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ja.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ja.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "プロジェクトのターゲット フレームワークです。", "symbols/Framework/displayName": "フレームワーク", "symbols/Framework/choices/net11.0/description": "ターゲット net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "(\"dotnet pack\" を使用して) プロジェクトのパッケージ化を有効にするかどうか。", "symbols/EnablePack/displayName": "パックを有効にする", "symbols/skipRestore/description": "指定した場合、作成時にプロジェクトの自動復元がスキップされます。", "symbols/skipRestore/displayName": "復元のスキップ", "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/openInEditor/description": "エディターで Tests.fs を開きます" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ko.json index 9afab3f13ffc..809daed191ad 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ko.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ko.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "프로젝트에 대한 대상 프레임워크입니다.", "symbols/Framework/displayName": "프레임워크", "symbols/Framework/choices/net11.0/description": "대상 net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "프로젝트에 대해 패키징(\"dotnet pack\"을 통해)을 활성화할지 여부", "symbols/EnablePack/displayName": "팩 사용", "symbols/skipRestore/description": "지정된 경우, 프로젝트 생성 시 자동 복원을 건너뜁니다.", "symbols/skipRestore/displayName": "복원 건너뛰기", "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/openInEditor/description": "편집기에서 Tests.fs 열기" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.pl.json index 977bd2720f76..3f3c434c128d 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.pl.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.pl.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Platforma docelowa dla tego projektu.", "symbols/Framework/displayName": "Struktura", "symbols/Framework/choices/net11.0/description": "Docelowa platforma net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Określa, czy włączyć pakowanie (za pośrednictwem „pakietu dotnet”) dla projektu.", "symbols/EnablePack/displayName": "Włącz pakiet", "symbols/skipRestore/description": "Jeśli ta opcja jest określona, pomija automatyczne przywracanie projektu podczas tworzenia.", "symbols/skipRestore/displayName": "Pomiń przywracanie", "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/openInEditor/description": "Otwiera plik Tests.fs w edytorze" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.pt-BR.json index 86cf44ae43a2..24f8d0754e8a 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.pt-BR.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "A estrutura de destino para o projeto.", "symbols/Framework/displayName": "Estrutura", "symbols/Framework/choices/net11.0/description": "net11.0 de destino", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Se deseja ou não habilitar o empacotamento (via \"dotnet pack\") para o projeto.", "symbols/EnablePack/displayName": "Habilitar pacote", "symbols/skipRestore/description": "Se especificado, ignora a restauração automática do projeto na criação.", "symbols/skipRestore/displayName": "Ignorar restauração", "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/openInEditor/description": "Abre o Tests.fs no editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ru.json index 4416751a6600..4f9e8bf3c3d6 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ru.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.ru.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Целевая платформа для проекта.", "symbols/Framework/displayName": "Платформа", "symbols/Framework/choices/net11.0/description": "Целевая платформа .NET 10.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Следует ли включить упаковку (через \"dotnet pack\") для проекта.", "symbols/EnablePack/displayName": "Включить пакет", "symbols/skipRestore/description": "Если указано, пропускает автоматическое восстановление проекта при создании.", "symbols/skipRestore/displayName": "Пропустить восстановление", "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/openInEditor/description": "Открывает Tests.fs в редакторе" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.tr.json index efd2bc94bfaf..ce579935730b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.tr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.tr.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Projenin hedef çerçevesi.", "symbols/Framework/displayName": "Çerçeve", "symbols/Framework/choices/net11.0/description": "Hedef net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Proje için paketlemeyi etkinleştirip etkinleştirmeme ayarı ( \"dotnet pack\" üzerinden).", "symbols/EnablePack/displayName": "Paketi etkinleştir", "symbols/skipRestore/description": "Belirtilmişse, oluşturma anında projenin otomatik geri yüklenmesini atlar.", "symbols/skipRestore/displayName": "Geri yüklemeyi atla", "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/openInEditor/description": "Tests.fs'yi düzenleyicide açar" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.zh-Hans.json index 62c13d1822aa..0f3d235e0db9 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "项目的目标框架。", "symbols/Framework/displayName": "框架", "symbols/Framework/choices/net11.0/description": "目标 net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "是否(通过 \"dotnet pack\")为项目启用打包。", "symbols/EnablePack/displayName": "启用包", "symbols/skipRestore/description": "如果指定,则在创建时跳过项目的自动还原。", "symbols/skipRestore/displayName": "跳过还原", "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/openInEditor/description": "在编辑器中打开 Tests.fs" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.zh-Hant.json index 15b6c04827af..d9a30481c71e 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "專案的目標架構。", "symbols/Framework/displayName": "架構", "symbols/Framework/choices/net11.0/description": "目標 net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "是否要啟用專案的封裝 (透過 \"dotnet pack\")。", "symbols/EnablePack/displayName": "啟用壓縮", "symbols/skipRestore/description": "如果指定,則會在建立時跳過專案的自動還原。", "symbols/skipRestore/displayName": "跳過還原", "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/openInEditor/description": "在編輯器中開啟 Tests.fs" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/template.json index 9b508cdf6a9a..5ddbc52923f8 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/.template.config/template.json @@ -15,6 +15,18 @@ }, "sourceName": "Company.TestProject1", "preferNameDirectory": true, + "sources": [ + { + "modifiers": [ + { + "condition": "(XUnitVersion != \"v3\")", + "exclude": [ + "xunit.runner.json" + ] + } + ] + } + ], "symbols": { "TargetFrameworkOverride": { "type": "parameter", @@ -38,6 +50,43 @@ "replaces": "net11.0", "defaultValue": "net11.0" }, + "XUnitVersion": { + "type": "parameter", + "datatype": "choice", + "enableQuotelessLiterals": true, + "description": "The version of xUnit.net to use.", + "displayName": "xUnit.net version", + "defaultValue": "v2", + "choices": [ + { + "choice": "v2", + "description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility)." + }, + { + "choice": "v3", + "description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information." + } + ] + }, + "TestRunner": { + "type": "parameter", + "datatype": "choice", + "enableQuotelessLiterals": true, + "description": "Select the runner/platform.", + "displayName": "Test runner", + "isEnabled": "(XUnitVersion == v3)", + "defaultValue": "Microsoft.Testing.Platform", + "choices": [ + { + "choice": "Microsoft.Testing.Platform", + "description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information." + }, + { + "choice": "VSTest", + "description": "Use VSTest platform" + } + ] + }, "EnablePack": { "type": "parameter", "datatype": "bool", @@ -74,6 +123,25 @@ "id": "restoreNugetPackages", "continueOnError": true }, + { + "condition": "(XUnitVersion == \"v3\" && TestRunner == \"Microsoft.Testing.Platform\")", + "description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.", + "manualInstructions": [{ "text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform" }], + "actionId": "695A3659-EB40-4FF5-A6A6-C9C4E629FCB0", + "id": "addJsonProperty", + "args": { + "allowFileCreation": true, + "allowPathCreation": true, + "jsonFileName": "global.json", + "parentPropertyPath": "test", + "newJsonPropertyName": "runner", + "newJsonPropertyValue": "Microsoft.Testing.Platform", + "detectRepositoryRoot": true, + "includeAllDirectoriesInSearch": false, + "includeAllParentDirectoriesInSearch": true + }, + "continueOnError": true + }, { "condition": "(HostIdentifier != \"dotnetcli\" && HostIdentifier != \"dotnetcli-preview\")", "description": "Opens Tests.fs in the editor", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/Company.TestProject1.fsproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/Company.TestProject1.fsproj index 87dd7841f8bc..25d6cce5d159 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/Company.TestProject1.fsproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/Company.TestProject1.fsproj @@ -6,17 +6,40 @@ Company.TestProject1 true false + + Exe + + + true + + + + + + + + + + + + + + + + + - + + \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/xunit.runner.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/xunit.runner.json new file mode 100644 index 000000000000..3e04e18aa4e1 --- /dev/null +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-FSharp/xunit.runner.json @@ -0,0 +1,3 @@ +{ + "$schema": "https://xunit.net/schema/v3.1/xunit.runner.schema.json" +} diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/dotnetcli.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/dotnetcli.host.json index 6f20dff748c1..727f665b8100 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/dotnetcli.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/dotnetcli.host.json @@ -9,6 +9,14 @@ "Framework": { "longName": "framework" }, + "XUnitVersion": { + "shortName": "", + "longName": "xunit-version" + }, + "TestRunner": { + "shortName": "", + "longName": "test-runner" + }, "EnablePack": { "shortName": "p", "longName": "enable-pack" diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/ide.host.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/ide.host.json index ef689320bee2..45902415890b 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/ide.host.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/ide.host.json @@ -1,6 +1,18 @@ { "$schema": "https://json.schemastore.org/ide.host", "icon": "ide/icon.ico", + "symbolInfo": [ + { + "id": "XUnitVersion", + "isVisible": true, + "persistenceScope": "shared" + }, + { + "id": "TestRunner", + "isVisible": true, + "persistenceScope": "shared" + } + ], "tags": [ { "type": "platform", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.cs.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.cs.json index 1d76e2855e60..d478891a7c0d 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.cs.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.cs.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Cílová architektura pro projekt", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Cíl net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Určuje, jestli se má pro projekt povolit balení (přes „dotnet pack“).", "symbols/EnablePack/displayName": "Povolit balíček", "symbols/skipRestore/description": "Je-li zadáno, přeskočí automatické obnovení projektu při vytvoření.", "symbols/skipRestore/displayName": "Přeskočit obnovení", "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/openInEditor/description": "Otevře Class1.cs v editoru." } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.de.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.de.json index 9101e4d19017..b44b2522314d 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.de.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.de.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Das Zielframework für das Projekt.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Ziel.-net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Gibt an, ob die Paketerstellung (über \"dotnet pack\") für das Projekt aktiviert werden soll.", "symbols/EnablePack/displayName": "Paket aktivieren", "symbols/skipRestore/description": "Wenn angegeben, wird die automatische Wiederherstellung des Projekts beim Erstellen übersprungen.", "symbols/skipRestore/displayName": "Wiederherstellung überspringen", "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/openInEditor/description": "Öffnet Class1.cs“ im Editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.en.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.en.json index 0003f3eb62e4..394e93433c87 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.en.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.en.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Target net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Whether or not to enable packaging (via \"dotnet pack\") for the project.", "symbols/EnablePack/displayName": "Enable pack", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/skipRestore/displayName": "Skip restore", "postActions/restoreNugetPackages/description": "Restore NuGet packages required by this project.", "postActions/restoreNugetPackages/manualInstructions/default/text": "Run '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/openInEditor/description": "Opens Class1.cs in the editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.es.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.es.json index 4ea2cb87597a..04cc993323d1 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.es.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.es.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Marco de destino del proyecto.", "symbols/Framework/displayName": "Plataforma", "symbols/Framework/choices/net11.0/description": "Destino net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Indica si se va a habilitar o no el empaquetado (a través de \"dotnet pack\") para el proyecto.", "symbols/EnablePack/displayName": "Habilitar paquete", "symbols/skipRestore/description": "Si se especifica, se omite la restauración automática del proyecto durante la creación.", "symbols/skipRestore/displayName": "Omitir restauración", "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/openInEditor/description": "Abrir Class1.cs en el editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.fr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.fr.json index b1c52236a21a..ff0d392bdd64 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.fr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.fr.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Le cadre cible du projet.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "net11.0 cible", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Indique s’il faut activer ou non la création de packages (via « dotnet pack ») pour le projet.", "symbols/EnablePack/displayName": "Activer le pack", "symbols/skipRestore/description": "Si spécifié, ignore la restauration automatique du projet lors de la création.", "symbols/skipRestore/displayName": "Ignorer la restauration", "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/openInEditor/description": "Ouvre Class1.cs dans l’éditeur" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.it.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.it.json index c9717f8ebe69..cce9dc5de4d4 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.it.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.it.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Il framework di destinazione per il progetto.", "symbols/Framework/displayName": "Framework", "symbols/Framework/choices/net11.0/description": "Destinazione net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Indica se abilitare o meno la creazione del pacchetto (tramite \"dotnet pack\") per il progetto.", "symbols/EnablePack/displayName": "Abilita pacchetto", "symbols/skipRestore/description": "Se specificato, ignora il ripristino automatico del progetto durante la creazione.", "symbols/skipRestore/displayName": "Salta ripristino", "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/openInEditor/description": "Apre Class1.cs nell'editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ja.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ja.json index 5d1935afaa41..c5137d4e648c 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ja.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ja.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "プロジェクトのターゲット フレームワークです。", "symbols/Framework/displayName": "フレームワーク", "symbols/Framework/choices/net11.0/description": "ターゲット net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "(\"dotnet pack\" を使用して) プロジェクトのパッケージ化を有効にするかどうか。", "symbols/EnablePack/displayName": "パックを有効にする", "symbols/skipRestore/description": "指定した場合、作成時にプロジェクトの自動復元がスキップされます。", "symbols/skipRestore/displayName": "復元のスキップ", "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/openInEditor/description": "エディターで Class1.cs を開きます" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ko.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ko.json index 4f43081b779b..84830ddc3359 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ko.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ko.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "프로젝트에 대한 대상 프레임워크입니다.", "symbols/Framework/displayName": "프레임워크", "symbols/Framework/choices/net11.0/description": "대상 net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "프로젝트에 대해 패키징(\"dotnet pack\"을 통해)을 활성화할지 여부", "symbols/EnablePack/displayName": "팩 사용", "symbols/skipRestore/description": "지정된 경우, 프로젝트 생성 시 자동 복원을 건너뜁니다.", "symbols/skipRestore/displayName": "복원 건너뛰기", "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/openInEditor/description": "편집기에서 Class1.cs 열기" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.pl.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.pl.json index 9859cc61cea9..13a9df16180e 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.pl.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.pl.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Platforma docelowa dla tego projektu.", "symbols/Framework/displayName": "Struktura", "symbols/Framework/choices/net11.0/description": "Docelowa platforma net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Określa, czy włączyć pakowanie (za pośrednictwem „pakietu dotnet”) dla projektu.", "symbols/EnablePack/displayName": "Włącz pakiet", "symbols/skipRestore/description": "Jeśli ta opcja jest określona, pomija automatyczne przywracanie projektu podczas tworzenia.", "symbols/skipRestore/displayName": "Pomiń przywracanie", "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/openInEditor/description": "Otwiera plik Class1.cs w edytorze" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.pt-BR.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.pt-BR.json index b29d142212bd..dceea9ca3428 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.pt-BR.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.pt-BR.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "A estrutura de destino para o projeto.", "symbols/Framework/displayName": "Estrutura", "symbols/Framework/choices/net11.0/description": "net11.0 de destino", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Se deseja ou não habilitar o empacotamento (via \"dotnet pack\") para o projeto.", "symbols/EnablePack/displayName": "Habilitar pacote", "symbols/skipRestore/description": "Se especificado, ignora a restauração automática do projeto na criação.", "symbols/skipRestore/displayName": "Ignorar restauração", "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/openInEditor/description": "Abrir Class1.cs no editor" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ru.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ru.json index fe1d650e21a7..921b9820864f 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ru.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.ru.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Целевая платформа для проекта.", "symbols/Framework/displayName": "Платформа", "symbols/Framework/choices/net11.0/description": "Целевая платформа .NET 10.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Следует ли включить упаковку (через \"dotnet pack\") для проекта.", "symbols/EnablePack/displayName": "Включить пакет", "symbols/skipRestore/description": "Если указано, пропускает автоматическое восстановление проекта при создании.", "symbols/skipRestore/displayName": "Пропустить восстановление", "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/openInEditor/description": "Открывает файл Class1.cs в редакторе" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.tr.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.tr.json index c91a8e762889..6b7feb3aaec3 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.tr.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.tr.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "Projenin hedef çerçevesi.", "symbols/Framework/displayName": "Çerçeve", "symbols/Framework/choices/net11.0/description": "Hedef net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "Proje için paketlemeyi etkinleştirip etkinleştirmeme ayarı ( \"dotnet pack\" üzerinden).", "symbols/EnablePack/displayName": "Paketi etkinleştir", "symbols/skipRestore/description": "Belirtilmişse, oluşturma anında projenin otomatik geri yüklenmesini atlar.", "symbols/skipRestore/displayName": "Geri yüklemeyi atla", "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/openInEditor/description": "Düzenleyicide Class1.cs dosyasını açar" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json index e5908ba38368..b164182ceae0 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hans.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "项目的目标框架。", "symbols/Framework/displayName": "框架", "symbols/Framework/choices/net11.0/description": "目标 net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "是否(通过 \"dotnet pack\")为项目启用打包。", "symbols/EnablePack/displayName": "启用包", "symbols/skipRestore/description": "如果指定,则在创建时跳过项目的自动还原。", "symbols/skipRestore/displayName": "跳过还原", "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/openInEditor/description": "在编辑器中打开 Class1.cs" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json index 84b2a3b73a18..4f7a8621d4a0 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/localize/templatestrings.zh-Hant.json @@ -7,11 +7,21 @@ "symbols/Framework/description": "專案的目標架構。", "symbols/Framework/displayName": "架構", "symbols/Framework/choices/net11.0/description": "目標 net11.0", + "symbols/XUnitVersion/description": "The version of xUnit.net to use.", + "symbols/XUnitVersion/displayName": "xUnit.net version", + "symbols/XUnitVersion/choices/v2/description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility).", + "symbols/XUnitVersion/choices/v3/description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information.", + "symbols/TestRunner/description": "Select the runner/platform.", + "symbols/TestRunner/displayName": "Test runner", + "symbols/TestRunner/choices/Microsoft.Testing.Platform/description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information.", + "symbols/TestRunner/choices/VSTest/description": "Use VSTest platform", "symbols/EnablePack/description": "是否要啟用專案的封裝 (透過 \"dotnet pack\")。", "symbols/EnablePack/displayName": "啟用壓縮", "symbols/skipRestore/description": "如果指定,則會在建立時跳過專案的自動還原。", "symbols/skipRestore/displayName": "跳過還原", "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/openInEditor/description": "在編輯器中開啟 Class1.cs" } \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/template.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/template.json index 9090fd8cb0f4..1aeee4b607dd 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/template.json +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/.template.config/template.json @@ -15,6 +15,18 @@ }, "sourceName": "Company.TestProject1", "preferNameDirectory": true, + "sources": [ + { + "modifiers": [ + { + "condition": "(XUnitVersion != \"v3\")", + "exclude": [ + "xunit.runner.json" + ] + } + ] + } + ], "symbols": { "TargetFrameworkOverride": { "type": "parameter", @@ -38,6 +50,43 @@ "replaces": "net11.0", "defaultValue": "net11.0" }, + "XUnitVersion": { + "type": "parameter", + "datatype": "choice", + "enableQuotelessLiterals": true, + "description": "The version of xUnit.net to use.", + "displayName": "xUnit.net version", + "defaultValue": "v2", + "choices": [ + { + "choice": "v2", + "description": "Use xUnit.net v2 (deprecated, kept for backwards compatibility)." + }, + { + "choice": "v3", + "description": "Use xUnit.net v3 with Microsoft.Testing.Platform enabled by default. See https://xunit.net/docs/getting-started/v3/cmdline for more information." + } + ] + }, + "TestRunner": { + "type": "parameter", + "datatype": "choice", + "enableQuotelessLiterals": true, + "description": "Select the runner/platform.", + "displayName": "Test runner", + "isEnabled": "(XUnitVersion == v3)", + "defaultValue": "Microsoft.Testing.Platform", + "choices": [ + { + "choice": "Microsoft.Testing.Platform", + "description": "Use Microsoft.Testing.Platform. See https://aka.ms/mtp-overview for more information." + }, + { + "choice": "VSTest", + "description": "Use VSTest platform" + } + ] + }, "EnablePack": { "type": "parameter", "datatype": "bool", @@ -74,6 +123,25 @@ "id": "restoreNugetPackages", "continueOnError": true }, + { + "condition": "(XUnitVersion == \"v3\" && TestRunner == \"Microsoft.Testing.Platform\")", + "description": "Create or update 'global.json' file required by Microsoft.Testing.Platform.", + "manualInstructions": [{ "text": "Manually update or create 'global.json' file setting the test runner to Microsoft.Testing.Platform" }], + "actionId": "695A3659-EB40-4FF5-A6A6-C9C4E629FCB0", + "id": "addJsonProperty", + "args": { + "allowFileCreation": true, + "allowPathCreation": true, + "jsonFileName": "global.json", + "parentPropertyPath": "test", + "newJsonPropertyName": "runner", + "newJsonPropertyValue": "Microsoft.Testing.Platform", + "detectRepositoryRoot": true, + "includeAllDirectoriesInSearch": false, + "includeAllParentDirectoriesInSearch": true + }, + "continueOnError": true + }, { "condition": "(HostIdentifier != \"dotnetcli\" && HostIdentifier != \"dotnetcli-preview\")", "description": "Opens Class1.cs in the editor", diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj index f34b4aba4a86..d51cf0a4ef77 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/Company.TestProject1.vbproj @@ -6,13 +6,37 @@ TargetFrameworkOverride true false + + Exe + + + true + + + + + + + + + + + + + + + + + + - + + \ No newline at end of file diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/UnitTest1.vb b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/UnitTest1.vb index 62304b51f3f2..65ccac306737 100644 --- a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/UnitTest1.vb +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/UnitTest1.vb @@ -4,7 +4,9 @@ Imports Xunit Public Class UnitTest1 Sub TestSub() - +#If (XUnitVersion == "v3") + Assert.True(True) +#End If End Sub End Class diff --git a/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/xunit.runner.json b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/xunit.runner.json new file mode 100644 index 000000000000..3e04e18aa4e1 --- /dev/null +++ b/template_feed/Microsoft.DotNet.Common.ProjectTemplates.11.0/content/XUnit-VisualBasic/xunit.runner.json @@ -0,0 +1,3 @@ +{ + "$schema": "https://xunit.net/schema/v3.1/xunit.runner.schema.json" +} diff --git a/test/Microsoft.NET.Build.Tasks.Tests/GivenACheckForUnsupportedWinMDReferencesMultiThreading.cs b/test/Microsoft.NET.Build.Tasks.Tests/GivenACheckForUnsupportedWinMDReferencesMultiThreading.cs new file mode 100644 index 000000000000..7118398247c0 --- /dev/null +++ b/test/Microsoft.NET.Build.Tasks.Tests/GivenACheckForUnsupportedWinMDReferencesMultiThreading.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Build.Framework; + +namespace Microsoft.NET.Build.Tasks.UnitTests +{ + public class GivenACheckForUnsupportedWinMDReferencesMultiThreading + { + [Fact] + public void RelativeManagedReferencePath_ResolvesFromTaskEnvironment() + { + using var tte = new TaskTestEnvironment(); + + const string managedReference = "refs/managed.dll"; + const string winmdReference = "refs/fake.winmd"; + + tte.CreateProjectDirectory("refs"); + File.Copy(typeof(CheckForUnsupportedWinMDReferences).Assembly.Location, tte.GetProjectPath(managedReference)); + tte.CreateProjectFile(winmdReference, string.Empty); + + File.Exists(managedReference).Should().BeFalse("the process CWD is not the project directory"); + + var task = new CheckForUnsupportedWinMDReferences + { + BuildEngine = new MockBuildEngine(), + TaskEnvironment = tte.TaskEnvironment, + TargetFrameworkMoniker = ".NETCoreApp,Version=v5.0", + ReferencePaths = new ITaskItem[] + { + new MockTaskItem(managedReference, new Dictionary()), + new MockTaskItem(winmdReference, new Dictionary()), + }, + }; + + task.Execute().Should().BeFalse("the .winmd reference should still log an unsupported reference error"); + + var engine = (MockBuildEngine)task.BuildEngine; + engine.Errors.Should().ContainSingle() + .Which.Code.Should().Be("NETSDK1130", "the error should be the WinMD reference error, not a FileNotFound/IO error caused by resolving the managed reference against the wrong directory"); + } + } +} diff --git a/test/Microsoft.NET.Build.Tasks.Tests/GivenAFrameworkPackages.cs b/test/Microsoft.NET.Build.Tasks.Tests/GivenAFrameworkPackages.cs new file mode 100644 index 000000000000..18e16ccb76c1 --- /dev/null +++ b/test/Microsoft.NET.Build.Tasks.Tests/GivenAFrameworkPackages.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using Microsoft.Build.Framework; +using Microsoft.ComponentDetection.Detectors.NuGet; +using NuGet.Frameworks; + +namespace Microsoft.NET.Build.Tasks.UnitTests +{ + /// + /// Direct unit tests for , which after the + /// multithreaded-task migration takes an for the targeting pack root. These + /// exercise the method in isolation (the early-out guards, the missing-folder branch, and a successful + /// PackageOverrides.txt load) rather than only through . + /// + public class GivenAFrameworkPackages + { + private const string NetCoreApp = "Microsoft.NETCore.App"; + + private sealed class TestLogger : Logger + { + protected override void LogCore(in Message message) { } + } + + private static NuGetFramework Net10 => new NuGetFramework(".NETCoreApp", new Version(10, 0, 0)); + + private static AbsolutePath AbsolutePathFor(string path) => + TaskEnvironmentHelper.CreateForTest(Path.GetTempPath()).GetAbsolutePath(path); + + [Fact] + public void ItReturnsNullWhenFrameworkIsNotANetCoreAppPack() + { + // null framework and non-.NETCoreApp frameworks both short-circuit to null. + FrameworkPackages.LoadFrameworkPackagesFromPack(new TestLogger(), framework: null, NetCoreApp, AbsolutePathFor(Path.GetTempPath())) + .Should().BeNull("a null framework is not a .NETCoreApp targeting pack"); + + var netFramework = new NuGetFramework(".NETFramework", new Version(4, 7, 2)); + FrameworkPackages.LoadFrameworkPackagesFromPack(new TestLogger(), netFramework, NetCoreApp, AbsolutePathFor(Path.GetTempPath())) + .Should().BeNull("only .NETCoreApp frameworks have targeting pack data"); + } + + [Fact] + public void ItReturnsNullWhenTargetingPackFolderDoesNotExist() + { + var missingRoot = Path.Combine(Path.GetTempPath(), "fp-missing-" + Guid.NewGuid().ToString("N")); + + FrameworkPackages.LoadFrameworkPackagesFromPack(new TestLogger(), Net10, NetCoreApp, AbsolutePathFor(missingRoot)) + .Should().BeNull("a non-existent targeting pack folder yields no packages"); + } + + [Fact] + public void ItLoadsPackageOverridesFromTargetingPack() + { + var root = Path.Combine(Path.GetTempPath(), "fp-" + Guid.NewGuid().ToString("N")); + try + { + // /Microsoft.NETCore.App.Ref/10.0.0/data/PackageOverrides.txt + var overridesFile = Path.Combine(root, NetCoreApp + ".Ref", "10.0.0", "data", "PackageOverrides.txt"); + Directory.CreateDirectory(Path.GetDirectoryName(overridesFile)!); + File.WriteAllText(overridesFile, "Newtonsoft.Json|13.0.1"); + + var result = FrameworkPackages.LoadFrameworkPackagesFromPack(new TestLogger(), Net10, NetCoreApp, AbsolutePathFor(root)); + + result.Should().NotBeNull("a PackageOverrides.txt exists under the targeting pack root"); + result.Packages.Should().ContainKey("Newtonsoft.Json"); + result.Packages["Newtonsoft.Json"].ToString().Should().Be("13.0.1"); + } + finally + { + try { Directory.Delete(root, recursive: true); } catch { /* best-effort cleanup */ } + } + } + } +} diff --git a/test/Microsoft.NET.Build.Tasks.Tests/GivenAGetPackagesToPrune.cs b/test/Microsoft.NET.Build.Tasks.Tests/GivenAGetPackagesToPrune.cs new file mode 100644 index 000000000000..290add75b50e --- /dev/null +++ b/test/Microsoft.NET.Build.Tasks.Tests/GivenAGetPackagesToPrune.cs @@ -0,0 +1,182 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Microsoft.NET.Build.Tasks.UnitTests +{ + /// + /// Functional tests for focused on how the task + /// resolves PrunePackageDataRoot and TargetingPackRoots through + /// . These tests pass RELATIVE paths and verify that + /// the task reads the on-disk data from the right place even when the process + /// current working directory differs from the project directory. + /// + public class GivenAGetPackagesToPrune + { + private const string NetCoreApp = "Microsoft.NETCore.App"; + private const string TargetFrameworkVersion = "10.0"; + + private static GetPackagesToPrune CreateTask(TaskTestEnvironment env, string targetingPackRoots, string prunePackageDataRoot, bool allowMissing = false) + { + return CreateTask(env, new[] { targetingPackRoots }, prunePackageDataRoot, allowMissing); + } + + private static GetPackagesToPrune CreateTask(TaskTestEnvironment env, string[] targetingPackRoots, string prunePackageDataRoot, bool allowMissing = false) + { + var frameworkReference = new TaskItem(NetCoreApp); + var targetingPack = new TaskItem(NetCoreApp); + targetingPack.SetMetadata("RuntimeFrameworkName", NetCoreApp); + + return new GetPackagesToPrune + { + BuildEngine = new MockNeverCacheBuildEngine4(), + TaskEnvironment = env.TaskEnvironment, + TargetFrameworkIdentifier = ".NETCoreApp", + TargetFrameworkVersion = TargetFrameworkVersion, + FrameworkReferences = new ITaskItem[] { frameworkReference }, + TargetingPacks = new ITaskItem[] { targetingPack }, + TargetingPackRoots = targetingPackRoots, + PrunePackageDataRoot = prunePackageDataRoot, + AllowMissingPrunePackageData = allowMissing, + LoadPrunePackageDataFromNearestFramework = false, + }; + } + + [Fact] + public void ItResolvesPrunePackageDataRootRelativeToTaskEnvironmentProjectDirectory() + { + using var env = new TaskTestEnvironment(); + + // Lay out a PackageOverrides.txt at /PrunePackageData/// + const string prunePackageDataRelative = "PrunePackageData"; + env.CreateProjectFile( + Path.Combine(prunePackageDataRelative, TargetFrameworkVersion, NetCoreApp, "PackageOverrides.txt"), + "Newtonsoft.Json|13.0.1"); + + var task = CreateTask(env, targetingPackRoots: env.GetProjectPath("targetingpacks"), prunePackageDataRelative); + + task.Execute().Should().BeTrue( + "PrunePackageDataRoot is relative and must be resolved against TaskEnvironment.ProjectDirectory, not the process CWD"); + + task.PackagesToPrune.Should().ContainSingle() + .Which.ItemSpec.Should().Be("Newtonsoft.Json"); + } + + [Fact] + public void ItResolvesTargetingPackRootsRelativeToTaskEnvironmentProjectDirectory() + { + using var env = new TaskTestEnvironment(); + + // Lay out a targeting-pack PackageOverrides.txt at + // /packs/Microsoft.NETCore.App.Ref/..0/data/PackageOverrides.txt + const string targetingPackRootRelative = "packs"; + env.CreateProjectFile( + Path.Combine( + targetingPackRootRelative, + NetCoreApp + ".Ref", + TargetFrameworkVersion + ".0", + "data", + "PackageOverrides.txt"), + "Newtonsoft.Json|13.0.1"); + + // Point PrunePackageDataRoot at an existing-but-empty directory so the task falls back + // to the targeting pack lookup (LoadPackagesToPruneFromPrunePackageData returns null). + const string emptyPruneDataRelative = "EmptyPruneData"; + env.CreateProjectDirectory(emptyPruneDataRelative); + + var task = CreateTask(env, targetingPackRoots: targetingPackRootRelative, prunePackageDataRoot: emptyPruneDataRelative); + + task.Execute().Should().BeTrue( + "TargetingPackRoots is relative and must be resolved against TaskEnvironment.ProjectDirectory, not the process CWD"); + + task.PackagesToPrune.Should().ContainSingle() + .Which.ItemSpec.Should().Be("Newtonsoft.Json"); + } + + [Fact] + public void ItIgnoresEmptyTargetingPackRootEntries() + { + using var env = new TaskTestEnvironment(); + + // Provide valid prune data so the task can succeed without any targeting pack roots. + const string prunePackageDataRelative = "PrunePackageData"; + env.CreateProjectFile( + Path.Combine(prunePackageDataRelative, TargetFrameworkVersion, NetCoreApp, "PackageOverrides.txt"), + "Newtonsoft.Json|13.0.1"); + + var task = CreateTask(env, targetingPackRoots: string.Empty, prunePackageDataRelative); + + // An empty string in TargetingPackRoots must be skipped without throwing from + // TaskEnvironment.GetAbsolutePath(""). + task.Execute().Should().BeTrue( + "empty entries in TargetingPackRoots should be silently skipped, preserving pre-migration behavior"); + + task.PackagesToPrune.Should().ContainSingle() + .Which.ItemSpec.Should().Be("Newtonsoft.Json"); + } + + [Fact] + public void ItDoesNotReuseCachedDataForDifferentResolvedTargetingPackRoots() + { + using var env = new TaskTestEnvironment(); + + // Two roots with the SAME framework values but DIFFERENT data. The build-wide cache key + // must include the resolved roots; otherwise the second task would incorrectly reuse the + // first one's packages. + const string rootA = "packs-a"; + const string rootB = "packs-b"; + env.CreateProjectFile( + Path.Combine(rootA, NetCoreApp + ".Ref", TargetFrameworkVersion + ".0", "data", "PackageOverrides.txt"), + "Newtonsoft.Json|13.0.1"); + env.CreateProjectFile( + Path.Combine(rootB, NetCoreApp + ".Ref", TargetFrameworkVersion + ".0", "data", "PackageOverrides.txt"), + "System.Text.Json|8.0.0"); + + // Empty-but-existing prune data so both fall back to the targeting pack lookup. + const string emptyPruneDataRelative = "EmptyPruneData"; + env.CreateProjectDirectory(emptyPruneDataRelative); + + // A SHARED caching engine across both task runs (MockBuildEngine caches by CacheKey). + var sharedEngine = new MockBuildEngine(); + + var taskA = CreateTask(env, targetingPackRoots: rootA, prunePackageDataRoot: emptyPruneDataRelative); + taskA.BuildEngine = sharedEngine; + taskA.Execute().Should().BeTrue(); + taskA.PackagesToPrune.Should().ContainSingle().Which.ItemSpec.Should().Be("Newtonsoft.Json"); + + var taskB = CreateTask(env, targetingPackRoots: rootB, prunePackageDataRoot: emptyPruneDataRelative); + taskB.BuildEngine = sharedEngine; + taskB.Execute().Should().BeTrue(); + taskB.PackagesToPrune.Should().ContainSingle().Which.ItemSpec.Should().Be( + "System.Text.Json", + "different resolved targeting pack roots must not collide in the build-wide cache"); + } + + [Fact] + public void ItReusesCachedDataForIdenticalInputs() + { + using var env = new TaskTestEnvironment(); + + const string prunePackageDataRelative = "PrunePackageData"; + env.CreateProjectFile( + Path.Combine(prunePackageDataRelative, TargetFrameworkVersion, NetCoreApp, "PackageOverrides.txt"), + "Newtonsoft.Json|13.0.1"); + + var sharedEngine = new MockBuildEngine(); + + var first = CreateTask(env, targetingPackRoots: "packs", prunePackageDataRelative); + first.BuildEngine = sharedEngine; + first.Execute().Should().BeTrue(); + + var second = CreateTask(env, targetingPackRoots: "packs", prunePackageDataRelative); + second.BuildEngine = sharedEngine; + second.Execute().Should().BeTrue(); + + // The second run with identical inputs should hit the cache and return the very same array. + second.PackagesToPrune.Should().BeSameAs(first.PackagesToPrune, + "identical framework values and resolved roots should produce a cache hit"); + } + } +} diff --git a/test/Microsoft.NET.Build.Tasks.Tests/GivenAPickBestRidMultiThreading.cs b/test/Microsoft.NET.Build.Tasks.Tests/GivenAPickBestRidMultiThreading.cs new file mode 100644 index 000000000000..bb71039acd40 --- /dev/null +++ b/test/Microsoft.NET.Build.Tasks.Tests/GivenAPickBestRidMultiThreading.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Build.Framework; + +namespace Microsoft.NET.Build.Tasks.UnitTests +{ + public class GivenAPickBestRidMultiThreading + { + private const string RuntimeGraphContent = @"{ + ""runtimes"": { + ""any"": { ""#import"": [""base""] }, + ""base"": { ""#import"": [] }, + ""win"": { ""#import"": [""any""] }, + ""win-x64"": { ""#import"": [""win""] } + } + }"; + + [Fact] + public void ItResolvesRelativeRuntimeGraphPathAgainstProjectDirectory() + { + var projectDir = Path.Combine(Path.GetTempPath(), "pickbestrid-relpath-" + Guid.NewGuid().ToString("N")); + var decoyCwd = Path.Combine(Path.GetTempPath(), "pickbestrid-decoy-" + Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(Path.Combine(projectDir, "sub")); + Directory.CreateDirectory(decoyCwd); + var savedCwd = Directory.GetCurrentDirectory(); + try + { + var relativePath = Path.Combine("sub", "runtime.json"); + File.WriteAllText(Path.Combine(projectDir, relativePath), RuntimeGraphContent); + + // Set CWD to a directory that does NOT contain the runtime graph file. + // If the task incorrectly used CWD, File.Exists would fail. + Directory.SetCurrentDirectory(decoyCwd); + + var task = new PickBestRid + { + BuildEngine = new MockBuildEngine(), + TaskEnvironment = TaskEnvironmentHelper.CreateForTest(projectDir), + RuntimeGraphPath = relativePath, + TargetRid = "win-x64", + SupportedRids = new[] { "any", "win", "win-x64" } + }; + + task.Execute().Should().BeTrue(); + task.MatchingRid.Should().Be("win-x64"); + } + finally + { + Directory.SetCurrentDirectory(savedCwd); + if (Directory.Exists(projectDir)) Directory.Delete(projectDir, true); + if (Directory.Exists(decoyCwd)) Directory.Delete(decoyCwd, true); + } + } + + [Fact] + public void MissingFileErrorContainsOriginalRelativePathNotAbsolutized() + { + var projectDir = Path.Combine(Path.GetTempPath(), "pickbestrid-err-" + Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(projectDir); + try + { + var relativePath = "definitely-missing.json"; + + var mockEngine = new MockBuildEngine(); + var task = new PickBestRid + { + BuildEngine = mockEngine, + TaskEnvironment = TaskEnvironmentHelper.CreateForTest(projectDir), + RuntimeGraphPath = relativePath, + TargetRid = "win-x64", + SupportedRids = new[] { "any", "win" } + }; + + task.Execute().Should().BeFalse(); + task.MatchingRid.Should().BeNull(); + + mockEngine.Errors.Should().HaveCount(1); + var message = mockEngine.Errors[0].Message; + message.Should().Contain(relativePath, "the original user-supplied path must appear in the error"); + message.Should().NotContain(projectDir, "the absolutized path must not leak into the error message"); + } + finally + { + if (Directory.Exists(projectDir)) Directory.Delete(projectDir, true); + } + } + + [Theory] + [InlineData(null)] + [InlineData("")] + public void EmptyRuntimeGraphPathLogsMissingFileError(string? runtimeGraphPath) + { + var mockEngine = new MockBuildEngine(); + var task = new PickBestRid + { + BuildEngine = mockEngine, + TaskEnvironment = TaskEnvironmentHelper.CreateForTest(), + RuntimeGraphPath = runtimeGraphPath!, + TargetRid = "win-x64", + SupportedRids = new[] { "any", "win" } + }; + + task.Execute().Should().BeFalse(); + task.MatchingRid.Should().BeNull(); + + mockEngine.Errors.Should().HaveCount(1); + mockEngine.Errors[0].Message.Should().Contain("does not exist"); + } + } +} diff --git a/test/Microsoft.NET.Build.Tasks.Tests/GivenAResolvePackageFileConflictsMultiThreading.cs b/test/Microsoft.NET.Build.Tasks.Tests/GivenAResolvePackageFileConflictsMultiThreading.cs new file mode 100644 index 000000000000..31d447d1a95b --- /dev/null +++ b/test/Microsoft.NET.Build.Tasks.Tests/GivenAResolvePackageFileConflictsMultiThreading.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using FluentAssertions; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Microsoft.NET.Build.Tasks.ConflictResolution; +using Xunit; + +namespace Microsoft.NET.Build.Tasks.UnitTests; + +[Collection(nameof(CwdSensitiveCollection))] +public class GivenAResolvePackageFileConflictsMultiThreading : IDisposable +{ + private readonly string _originalCwd = Directory.GetCurrentDirectory(); + private readonly string _testRoot = Path.Combine(AppContext.BaseDirectory, "rpfc_test_" + Guid.NewGuid().ToString("N")); + + public void Dispose() + { + Directory.SetCurrentDirectory(_originalCwd); + try { Directory.Delete(_testRoot, true); } catch { } + } + + /// + /// PlatformManifests with a relative ItemSpec must be resolved against the task's + /// ProjectDirectory (via TaskEnvironment), not the process CWD. We verify this by + /// pointing at a manifest that exists relative to the project directory but not the + /// CWD: if path resolution were CWD-based, the task would log CouldNotLoadPlatformManifest. + /// + [Fact] + public void PlatformManifest_ResolvesRelativePathAgainstProjectDir() + { + var projectDir = CreateTempDir(); + var decoyDir = CreateTempDir(); + + var manifestRelPath = Path.Combine("manifests", "PlatformManifest.txt"); + var manifestPath = Path.Combine(projectDir, manifestRelPath); + Directory.CreateDirectory(Path.GetDirectoryName(manifestPath)!); + File.WriteAllText(manifestPath, "System.Runtime.dll|Platform.Package|9.0.0.0|9.0.0.0"); + + var copyLocalRelPath = Path.Combine("packages", "System.Runtime.dll"); + CreateFile(Path.Combine(projectDir, copyLocalRelPath)); + var copyLocalItem = new MockTaskItem(copyLocalRelPath, new Dictionary + { + { "NuGetPackageId", "Package.Low" }, + { "AssemblyVersion", "1.0.0.0" }, + { "FileVersion", "1.0.0.0" } + }); + + Directory.SetCurrentDirectory(decoyDir); + + var engine = new MockBuildEngine(); + var task = CreateTask(engine); + task.TaskEnvironment = TaskEnvironmentHelper.CreateForTest(projectDir); + task.PlatformManifests = new ITaskItem[] { new MockTaskItem(manifestRelPath, new Dictionary()) }; + task.ReferenceCopyLocalPaths = new ITaskItem[] { copyLocalItem }; + + task.Execute().Should().BeTrue("relative PlatformManifests should resolve against ProjectDirectory"); + engine.Errors.Should().BeEmpty("manifest was found via ProjectDirectory-relative resolution"); + task.ReferenceCopyLocalPathsWithoutConflicts.Should().BeEmpty( + "the platform manifest item from ProjectDirectory should win the runtime conflict"); + + var conflict = task.Conflicts.Should().ContainSingle().Which; + conflict.ItemSpec.Should().Be(copyLocalRelPath); + conflict.GetMetadata("NuGetPackageId").Should().Be("Package.Low"); + conflict.GetMetadata(nameof(ConflictItemType)).Should().Be(ConflictItemType.CopyLocal.ToString()); + } + + [Fact] + public void PlatformManifest_EmptyPathLogsAndSkips() + { + var projectDir = CreateTempDir(); + + var engine = new MockBuildEngine(); + var task = CreateTask(engine); + task.TaskEnvironment = TaskEnvironmentHelper.CreateForTest(projectDir); + task.PlatformManifests = new ITaskItem[] { new MockTaskItem(string.Empty, new Dictionary()) }; + + task.Execute().Should().BeFalse("empty PlatformManifests should log and skip without throwing"); + var error = engine.Errors.Should().ContainSingle().Which; + error.Message.Should().NotContain(projectDir, "the original empty path must not be absolutized"); + } + + /// + /// TargetFrameworkDirectories with a relative ItemSpec must preserve the pre-migration + /// behavior: the derived FrameworkList.xml path is invalid because it is not rooted. + /// + [Fact] + public void TargetFrameworkDirectories_RelativePathLogsNotRootedOriginalPath() + { + var projectDir = CreateTempDir(); + var decoyDir = CreateTempDir(); + + var targetFrameworkRelPath = "refpack"; + var expectedFrameworkListPath = Path.Combine(targetFrameworkRelPath, "RedistList", "FrameworkList.xml"); + CreateFrameworkList(Path.Combine(projectDir, targetFrameworkRelPath), "System.Runtime", "9.0.0.0"); + + var referenceRelPath = Path.Combine("packages", "System.Runtime.dll"); + CreateFile(Path.Combine(projectDir, referenceRelPath)); + + Directory.SetCurrentDirectory(decoyDir); + + var engine = new MockBuildEngine(); + var task = CreateTask(engine); + task.TaskEnvironment = TaskEnvironmentHelper.CreateForTest(projectDir); + task.TargetFrameworkDirectories = new ITaskItem[] { new MockTaskItem(targetFrameworkRelPath, new Dictionary()) }; + task.References = new ITaskItem[] + { + new MockTaskItem(referenceRelPath, new Dictionary + { + { "NuGetPackageId", "Package.Low" }, + { "AssemblyVersion", "1.0.0.0" }, + { "FileVersion", "1.0.0.0" } + }) + }; + + task.Execute().Should().BeFalse("relative TargetFrameworkDirectories should remain invalid"); + var error = engine.Errors.Should().ContainSingle().Which; + error.Message.Should().Contain(expectedFrameworkListPath, "the original relative path must be preserved in the error"); + error.Message.Should().NotContain(projectDir, "the relative path must not be silently absolutized against ProjectDirectory"); + engine.RegisteredTaskObjects.Should().BeEmpty(); + } + + private string CreateTempDir() + { + var dir = Path.Combine(_testRoot, Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(dir); + return dir; + } + + private static void CreateFrameworkList(string targetFrameworkDirectory, string assemblyName, string version) + { + var redistListDir = Path.Combine(targetFrameworkDirectory, "RedistList"); + Directory.CreateDirectory(redistListDir); + File.WriteAllText(Path.Combine(redistListDir, "FrameworkList.xml"), + $""); + } + + private static void CreateFile(string path) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)!); + File.WriteAllBytes(path, Array.Empty()); + } + + private static ResolvePackageFileConflicts CreateTask(MockBuildEngine engine) + { + var task = new ResolvePackageFileConflicts(); + task.BuildEngine = engine; + return task; + } +} diff --git a/test/Microsoft.NET.Build.Tasks.Tests/GivenTasksUseAbsolutePaths.cs b/test/Microsoft.NET.Build.Tasks.Tests/GivenTasksUseAbsolutePaths.cs index 26212abb1d40..92367c3536a3 100644 --- a/test/Microsoft.NET.Build.Tasks.Tests/GivenTasksUseAbsolutePaths.cs +++ b/test/Microsoft.NET.Build.Tasks.Tests/GivenTasksUseAbsolutePaths.cs @@ -362,6 +362,94 @@ public void ConflictItem_WithoutTaskEnvironment_ShouldKeepExistingRelativePathBe conflictItem.DisplayName.Should().Be($"CopyLocal:{existingPath}", "display strings should not be absolutized"); } + [Fact] + public void ConflictItem_WithTaskEnvironment_ExistsResolvesRelativePathToProjectDirectory() + { + const string relativePath = "libs/existing.dll"; + + _env.CreateProjectFile(relativePath, string.Empty); + + File.Exists(relativePath).Should().BeFalse("file should NOT be findable relative to the spawn CWD"); + + var item = CreateCopyLocalConflictItem(relativePath, assemblyVersion: string.Empty); + var conflictItem = new ConflictItem(item, ConflictItemType.CopyLocal, _env.TaskEnvironment); + + conflictItem.Exists.Should().BeTrue( + "Exists must resolve the relative HintPath against the TaskEnvironment's project directory, not the process CWD"); + } + + [Fact] + public void ConflictItem_WithTaskEnvironment_FileVersionReadsFileViaProjectDirectory() + { + // Copy a real managed assembly (this test assembly) into the project directory so + // FileUtilities.GetFileVersion has something to read. If path resolution were CWD-based, + // the file would not be found and FileVersion would be null. + var sourceAssemblyPath = typeof(GivenTasksUseAbsolutePaths).Assembly.Location; + const string relativePath = "libs/sample.dll"; + var targetPath = _env.GetProjectPath(relativePath); + Directory.CreateDirectory(Path.GetDirectoryName(targetPath)!); + File.Copy(sourceAssemblyPath, targetPath, overwrite: true); + + File.Exists(relativePath).Should().BeFalse("file should NOT be findable relative to the spawn CWD"); + + // No AssemblyVersion/FileVersion metadata -> ConflictItem must fall back to reading the file. + var item = new MockTaskItem(relativePath, new Dictionary + { + ["HintPath"] = relativePath, + }); + var conflictItem = new ConflictItem(item, ConflictItemType.CopyLocal, _env.TaskEnvironment); + + conflictItem.FileVersion.Should().NotBeNull( + "FileVersion must be obtainable via TaskEnvironment-resolved path even when the process CWD is wrong"); + } + + [Fact] + public void ConflictItem_WithTaskEnvironment_SourcePathAndDisplayNamePreserveOriginalRelativePath() + { + const string relativePath = "libs/existing.dll"; + + _env.CreateProjectFile(relativePath, string.Empty); + + var item = CreateCopyLocalConflictItem(relativePath, "1.0.0.0"); + var conflictItem = new ConflictItem(item, ConflictItemType.CopyLocal, _env.TaskEnvironment); + + // Trigger file access first so the lazy absolutized path is computed; it must still not + // leak into the user-visible string properties. + _ = conflictItem.Exists; + + conflictItem.SourcePath.Should().Be(relativePath, + "SourcePath is surfaced to users and must preserve the original relative value, not the absolutized form"); + conflictItem.FileName.Should().Be(Path.GetFileName(relativePath), + "FileName is derived from the original ItemSpec and must not include directory parts from absolutization"); + conflictItem.DisplayName.Should().Be($"CopyLocal:{relativePath}", + "DisplayName is used in diagnostics and must not leak the absolutized path"); + } + + [Fact] + public void ConflictItem_WithTaskEnvironment_HonorsMetadataAndDoesNotAccessFile() + { + // Point at a file that does NOT exist anywhere; if anything other than Exists touches the + // file system, AssemblyVersion/FileVersion would be null. They must come from metadata. + const string nonexistentRelativePath = "does/not/exist.dll"; + + File.Exists(_env.GetProjectPath(nonexistentRelativePath)).Should().BeFalse(); + + var item = new MockTaskItem(nonexistentRelativePath, new Dictionary + { + ["HintPath"] = nonexistentRelativePath, + ["AssemblyVersion"] = "2.5.0.0", + ["FileVersion"] = "3.4.2.1", + }); + var conflictItem = new ConflictItem(item, ConflictItemType.CopyLocal, _env.TaskEnvironment); + + conflictItem.AssemblyVersion.Should().Be(new Version(2, 5, 0, 0), + "metadata-supplied AssemblyVersion must be honored without triggering file I/O"); + conflictItem.FileVersion.Should().Be(new Version(3, 4, 2, 1), + "metadata-supplied FileVersion must be honored without triggering file I/O"); + conflictItem.Exists.Should().BeFalse( + "Exists should still report the actual on-disk state via the TaskEnvironment-resolved path"); + } + private static ITaskItem CreateCopyLocalConflictItem(string relativeHintPath, string assemblyVersion) { return new MockTaskItem(relativeHintPath, new Dictionary diff --git a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs index d407bd9e4419..27df3cd7e0fe 100644 --- a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs +++ b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs @@ -560,7 +560,7 @@ public void It_fails_gracefully_if_targetframework_is_empty(bool useSolution) { string targetFramework = ""; TestInvalidTargetFramework("EmptyTargetFramework", targetFramework, useSolution, - $"The TargetFramework value '{targetFramework}' was not recognized"); + "The TargetFramework property is empty"); } [Theory] diff --git a/test/Microsoft.NET.Publish.Tests/GivenThatAPublishedDepsJsonShouldContainVersionInformation.cs b/test/Microsoft.NET.Publish.Tests/GivenThatAPublishedDepsJsonShouldContainVersionInformation.cs index 6ba2881ab4e6..d66fd8838d45 100644 --- a/test/Microsoft.NET.Publish.Tests/GivenThatAPublishedDepsJsonShouldContainVersionInformation.cs +++ b/test/Microsoft.NET.Publish.Tests/GivenThatAPublishedDepsJsonShouldContainVersionInformation.cs @@ -144,10 +144,14 @@ public static void Main() // (e.g. 8.0.22) may be installed rather than 8.0.0, so we need to discover it dynamically. string dotnetRoot = SdkTestContext.Current.ToolsetUnderTest.DotNetRoot; string sharedFxDir = Path.Combine(dotnetRoot, "shared", "Microsoft.NETCore.App"); - string rollForwardVersion = Directory.GetDirectories(sharedFxDir, "8.0.*") - .Select(d => Path.GetFileName(d)) - .OrderByDescending(v => v) - .FirstOrDefault() ?? "8.0.0"; + string rollForwardVersion = Directory.Exists(sharedFxDir) + ? Directory.GetDirectories(sharedFxDir, "8.0.*") + .Select(Path.GetFileName) + .Where(v => !string.IsNullOrEmpty(v) && Version.TryParse(v, out _)) + .OrderByDescending(v => Version.Parse(v)) + .FirstOrDefault() + : null + ?? "8.0.0"; var runAppCommand = new DotnetCommand(Log, "exec", "--fx-version", rollForwardVersion, exePath); diff --git a/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/GroupedFrameworkAssetsIntegrationTest.cs b/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/GroupedFrameworkAssetsIntegrationTest.cs new file mode 100644 index 000000000000..a1f9ce7d7aa4 --- /dev/null +++ b/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/GroupedFrameworkAssetsIntegrationTest.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. + +#nullable disable + +using System.Xml.Linq; +using Microsoft.AspNetCore.StaticWebAssets.Tasks; + +namespace Microsoft.NET.Sdk.StaticWebAssets.Tests +{ + public class GroupedFrameworkAssetsIntegrationTest(ITestOutputHelper log) + : IsolatedNuGetPackageFolderAspNetSdkBaselineTest(log, nameof(GroupedFrameworkAssetsIntegrationTest)) + { + // Regression coverage for the blazor.webassembly.js 404. A package ships an asset that is both a + // framework asset and a member of a group (as Microsoft.AspNetCore.Components.WebAssembly does for + // blazor.webassembly.js). The scenario is Package -> Library -> App: + // * The group is opt-in via the IncludeGroupedFrameworkAssets property set by the library, so + // inclusion is conditional. + // * When the library enables the group, the framework asset materializes into the library under the + // library base path (_content/) with its AssetGroups cleared. If AssetGroups is not + // cleared during materialization, downstream endpoint generation skips the asset and it 404s. + // * The materialized framework asset is a current-project asset of the library, so the app (which + // does not enable the group) does not include it at the root. + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Build_PackageToLibraryToApp_GroupedFrameworkAsset_IsConditionalAndMaterializedIntoLibrary(bool includeGroupedFrameworkAssets) + { + ProjectDirectory = CreateAspNetSdkTestAsset("GroupedFrameworkAssetsSample", identifier: includeGroupedFrameworkAssets.ToString()) + .WithProjectChanges((path, document) => + { + if (Path.GetFileName(path) == "GroupedFrameworkLibrary.csproj") + { + // Only the library opts into the group, so the app does not re-include the asset. + var propertyGroup = document.Root.Descendants("TargetFramework").First().Parent; + propertyGroup.Add( + new XElement("IncludeGroupedFrameworkAssets", includeGroupedFrameworkAssets.ToString())); + } + }); + + var pack = CreatePackCommand(ProjectDirectory, "GroupedFrameworkPackage"); + ExecuteCommand(pack).Should().Pass(); + ClearCachedPackage("groupedframeworkpackage"); + + var build = CreateBuildCommand(ProjectDirectory, "GroupedFrameworkApp"); + ExecuteCommand(build).Should().Pass(); + + var libraryManifest = LoadBuildManifest( + Path.Combine(ProjectDirectory.TestRoot, "GroupedFrameworkLibrary", "obj", "Debug", DefaultTfm)); + var appManifest = LoadBuildManifest(build.GetIntermediateDirectory(DefaultTfm, "Debug").ToString()); + + // The materialized asset lives under fx\ (the originating framework + // package), but is owned by the consuming library (SourceId, BasePath are remapped). + var libraryMaterializedJs = libraryManifest.Assets + .Where(a => a.RelativePath.Contains(".js") + && a.Identity.Contains(Path.Combine("fx", "GroupedFrameworkPackage"))) + .ToList(); + + if (includeGroupedFrameworkAssets) + { + libraryMaterializedJs.Should().NotBeEmpty( + "the grouped JS framework asset should be materialized into the library when the group is enabled"); + + foreach (var asset in libraryMaterializedJs) + { + // Materialized into the library, under the library base path. + asset.SourceId.Should().Be("GroupedFrameworkLibrary", + $"materialized framework asset {asset.RelativePath} should belong to the library"); + asset.BasePath.Should().Be("_content/GroupedFrameworkLibrary", + $"materialized framework asset {asset.RelativePath} should be under the library base path"); + + // AssetGroups must be cleared, otherwise endpoint generation skips the asset (the 404). + asset.AssetGroups.Should().BeNullOrEmpty( + $"materialized framework asset {asset.RelativePath} must have its AssetGroups cleared"); + } + + // The framework asset is a current-project asset of the library, so the app does not + // include it at the root. + appManifest.Assets + .Where(a => a.RelativePath.Contains("feature") && a.BasePath == "/") + .Should().BeEmpty("the app should not include the library's framework asset at the root"); + } + else + { + // The group is not enabled, so the grouped framework asset is excluded entirely. + libraryMaterializedJs.Should().BeEmpty( + "the grouped JS framework asset should be excluded when the group is not enabled"); + } + } + + private static StaticWebAssetsManifest LoadBuildManifest(string intermediateOutputPath) + { + var path = Path.Combine(intermediateOutputPath, "staticwebassets.build.json"); + new FileInfo(path).Should().Exist(); + var manifest = StaticWebAssetsManifest.FromJsonBytes(File.ReadAllBytes(path)); + manifest.Should().NotBeNull(); + return manifest; + } + + // Clear the cached package so NuGet re-extracts from the freshly-packed nupkg. + private void ClearCachedPackage(string packageId) + { + var cached = Path.Combine(GetNuGetCachePath(), packageId); + if (Directory.Exists(cached)) + { + Directory.Delete(cached, recursive: true); + } + } + } +} diff --git a/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/ReadPackageAssetsManifestTest.cs b/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/ReadPackageAssetsManifestTest.cs index 1bc26855d0a1..1ce7486112fb 100644 --- a/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/ReadPackageAssetsManifestTest.cs +++ b/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/ReadPackageAssetsManifestTest.cs @@ -232,6 +232,31 @@ public void FrameworkAssets_MaterializedToIntermediateDirectory() emitted.GetMetadata("SourceId").Should().Be("ConsumerApp"); } + [Fact] + public void GroupedFrameworkAsset_HasAssetGroupsClearedAfterMaterialization() + { + // A framework asset that belongs to a group (e.g. blazor.webassembly.js in the + // BlazorWebAssembly group) passes group filtering when the group is declared, but + // must have its AssetGroups cleared once it is materialized as a current-project + // asset. Otherwise downstream endpoint generation treats it as a still-grouped + // asset, skips it, and the fingerprinted asset 404s at runtime. + var packageRoot = SetupPackageRoot("Microsoft.AspNetCore.Components.WebAssembly", + CreateManifestAsset("staticwebassets/_framework/blazor.webassembly.js", "_framework/blazor.webassembly.js", "/", "BlazorWebAssembly=enabled", "Framework")); + + var manifestItem = CreateManifestItem(packageRoot, "Microsoft.AspNetCore.Components.WebAssembly"); + + var task = CreateReadManifestTask( + new[] { manifestItem }, + new[] { CreateGroup("BlazorWebAssembly", "enabled", "Microsoft.AspNetCore.Components.WebAssembly") }); + task.Execute().Should().BeTrue(); + + task.Assets.Should().HaveCount(1); + + var emitted = task.Assets[0]; + emitted.GetMetadata("SourceType").Should().Be("Discovered"); + emitted.GetMetadata("AssetGroups").Should().BeEmpty("materialized framework assets must not retain group membership or endpoint generation will skip them"); + } + [Fact] public void InvalidManifestVersion_LogsError() { diff --git a/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/StaticWebAssetsGeneratePackagePropsFileMultiThreadingTest.cs b/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/StaticWebAssetsGeneratePackagePropsFileMultiThreadingTest.cs new file mode 100644 index 000000000000..3cf25d0246a0 --- /dev/null +++ b/test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/StaticWebAssetsGeneratePackagePropsFileMultiThreadingTest.cs @@ -0,0 +1,60 @@ +// 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.AspNetCore.StaticWebAssets.Tasks; +using Microsoft.Build.Framework; +using Moq; + +namespace Microsoft.AspNetCore.Razor.Tasks; + +// Test parallelization is disabled assembly-wide via +// [assembly:CollectionBehavior(DisableTestParallelization = true)] in +// LegacyStaticWebAssetsV1IntegrationTest.cs, which already isolates the +// process-CWD mutation this test performs. +public class StaticWebAssetsGeneratePackagePropsFileMultiThreadingTest +{ + [Fact] + public void WritesPropsFileRelativeToTaskEnvironmentProjectDirectory() + { + var testRoot = Path.Combine(AppContext.BaseDirectory, nameof(StaticWebAssetsGeneratePackagePropsFileMultiThreadingTest), Guid.NewGuid().ToString("N")); + var projectDir = Path.Combine(testRoot, "project"); + var spawnDir = Path.Combine(testRoot, "spawn"); + var projectOutputDir = Path.Combine(projectDir, "output"); + var spawnOutputDir = Path.Combine(spawnDir, "output"); + Directory.CreateDirectory(projectOutputDir); + Directory.CreateDirectory(spawnOutputDir); + + var currentDirectory = Directory.GetCurrentDirectory(); + try + { + Directory.SetCurrentDirectory(spawnDir); + + var buildEngine = new Mock(); + var task = new StaticWebAssetsGeneratePackagePropsFile + { + BuildEngine = buildEngine.Object, + TaskEnvironment = TaskEnvironment.CreateWithProjectDirectoryAndEnvironment(projectDir), + PropsFileImport = "Microsoft.AspNetCore.StaticWebAssets.props", + BuildTargetPath = Path.Combine("output", "props.xml") + }; + + task.Execute().Should().BeTrue(); + + var expectedPath = Path.Combine(projectDir, "output", "props.xml"); + File.Exists(expectedPath).Should().BeTrue("the file should be written under the project dir, not the process CWD"); + + var incorrectPath = Path.Combine(spawnDir, "output", "props.xml"); + File.Exists(incorrectPath).Should().BeFalse(); + } + finally + { + Directory.SetCurrentDirectory(currentDirectory); + if (Directory.Exists(testRoot)) + { + Directory.Delete(testRoot, recursive: true); + } + } + } +} diff --git a/test/TestAssets/TestProjects/DotnetRunDevicesWorkload/Devices.targets b/test/TestAssets/TestProjects/DotnetRunDevicesWorkload/Devices.targets new file mode 100644 index 000000000000..0a7f0e716417 --- /dev/null +++ b/test/TestAssets/TestProjects/DotnetRunDevicesWorkload/Devices.targets @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/DotnetRunDevicesWorkload/DotnetRunDevicesWorkload.csproj b/test/TestAssets/TestProjects/DotnetRunDevicesWorkload/DotnetRunDevicesWorkload.csproj new file mode 100644 index 000000000000..c80e3579ce15 --- /dev/null +++ b/test/TestAssets/TestProjects/DotnetRunDevicesWorkload/DotnetRunDevicesWorkload.csproj @@ -0,0 +1,44 @@ + + + + Exe + net9.0;$(CurrentTargetFramework) + false + + + + + + + + + + + $(IntermediateOutputPath)DeviceInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/DotnetRunDevicesWorkload/Program.cs b/test/TestAssets/TestProjects/DotnetRunDevicesWorkload/Program.cs new file mode 100644 index 000000000000..98662b384587 --- /dev/null +++ b/test/TestAssets/TestProjects/DotnetRunDevicesWorkload/Program.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace DotNetRunDevicesWorkload +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello from multi-targeted app!"); + Console.WriteLine($"Target Framework: {AppContext.TargetFrameworkName}"); + Console.WriteLine($"Runtime: {System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}"); + + // DeviceInfo class is generated at build time when Device property is set + Console.WriteLine($"Device: {DeviceInfo.Device}"); + Console.WriteLine($"RuntimeIdentifier: {DeviceInfo.RuntimeIdentifier}"); + } + } +} diff --git a/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkApp/GroupedFrameworkApp.csproj b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkApp/GroupedFrameworkApp.csproj new file mode 100644 index 000000000000..cb7453b55eb3 --- /dev/null +++ b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkApp/GroupedFrameworkApp.csproj @@ -0,0 +1,27 @@ + + + + $(AspNetTestTfm) + + + + false + + + + + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkApp/Program.cs b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkApp/Program.cs new file mode 100644 index 000000000000..0441593deead --- /dev/null +++ b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkApp/Program.cs @@ -0,0 +1,7 @@ +using Microsoft.AspNetCore.Builder; + +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); +app.MapStaticAssets(); +app.MapGet("/", () => "Hello World!"); +app.Run(); diff --git a/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkLibrary/GroupedFrameworkLibrary.csproj b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkLibrary/GroupedFrameworkLibrary.csproj new file mode 100644 index 000000000000..d1e73bcd2732 --- /dev/null +++ b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkLibrary/GroupedFrameworkLibrary.csproj @@ -0,0 +1,17 @@ + + + + $(AspNetTestTfm) + true + false + + + + false + + + + + + + diff --git a/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkLibrary/wwwroot/library-asset.txt b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkLibrary/wwwroot/library-asset.txt new file mode 100644 index 000000000000..fac4e09056d4 --- /dev/null +++ b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkLibrary/wwwroot/library-asset.txt @@ -0,0 +1 @@ +
library content
diff --git a/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkPackage/GroupedFrameworkPackage.csproj b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkPackage/GroupedFrameworkPackage.csproj new file mode 100644 index 000000000000..301fc5bc4620 --- /dev/null +++ b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkPackage/GroupedFrameworkPackage.csproj @@ -0,0 +1,34 @@ + + + + $(AspNetTestTfm) + true + © Microsoft + Grouped Framework Assets Test + Microsoft + Package shipping an asset that is both a framework asset and a group member (mirrors blazor.webassembly.js) + false + + + **/*.js + + $(AspNetTestPackageSource) + 1.0.0 + + + + false + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkPackage/StaticWebAssets.Groups.targets b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkPackage/StaticWebAssets.Groups.targets new file mode 100644 index 000000000000..f130ef02633e --- /dev/null +++ b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkPackage/StaticWebAssets.Groups.targets @@ -0,0 +1,7 @@ + + + + + + diff --git a/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkPackage/wwwroot/feature.js b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkPackage/wwwroot/feature.js new file mode 100644 index 000000000000..e08c9d05f45e --- /dev/null +++ b/test/TestAssets/TestProjects/GroupedFrameworkAssetsSample/GroupedFrameworkPackage/wwwroot/feature.js @@ -0,0 +1,2 @@ +// Framework bootstrapper script (grouped + framework asset, mirrors blazor.webassembly.js). +export function start() { } diff --git a/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/Lib/AsyncCalculator.cs b/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/Lib/AsyncCalculator.cs new file mode 100644 index 000000000000..ab30bf541047 --- /dev/null +++ b/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/Lib/AsyncCalculator.cs @@ -0,0 +1,38 @@ +namespace Lib +{ + public class AsyncCalculator + { + public async Task AddAsync(int a, int b) + { + await Task.Yield(); + return a + b; + } + + public async Task SubtractAsync(int a, int b) + { + await Task.Delay(1); + return a - b; + } + + public async Task MultiplyAsync(int a, int b) + { + await Task.Yield(); + int result = 0; + for (int i = 0; i < b; i++) + { + await Task.Yield(); + result += a; + } + return result; + } + + public async IAsyncEnumerable EnumerateAsync(int count) + { + for (int i = 0; i < count; i++) + { + await Task.Yield(); + yield return i; + } + } + } +} diff --git a/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/Lib/Lib.csproj b/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/Lib/Lib.csproj new file mode 100644 index 000000000000..02a102b88287 --- /dev/null +++ b/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/Lib/Lib.csproj @@ -0,0 +1,10 @@ + + + + + $(CurrentTargetFramework) + enable + enable + + + diff --git a/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/Test1.cs b/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/Test1.cs index 8bbbb841f05f..e0f04f8e645d 100644 --- a/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/Test1.cs +++ b/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/Test1.cs @@ -1,10 +1,14 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using Lib; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace TestProject { [TestClass] public sealed class Test1 { + private readonly AsyncCalculator _calculator = new(); + [TestMethod] public void TestMethod1() { @@ -16,5 +20,37 @@ public void TestMethod2() { Assert.AreEqual(1, 2); } + + [TestMethod] + public async Task AddAsync_Works() + { + int result = await _calculator.AddAsync(2, 3); + Assert.AreEqual(5, result); + } + + [TestMethod] + public async Task SubtractAsync_Works() + { + int result = await _calculator.SubtractAsync(10, 4); + Assert.AreEqual(6, result); + } + + [TestMethod] + public async Task MultiplyAsync_Works() + { + int result = await _calculator.MultiplyAsync(3, 4); + Assert.AreEqual(12, result); + } + + [TestMethod] + public async Task EnumerateAsync_Works() + { + int sum = 0; + await foreach (int i in _calculator.EnumerateAsync(5)) + { + sum += i; + } + Assert.AreEqual(10, sum); + } } } diff --git a/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/TestProject.csproj b/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/TestProject.csproj index 7bf348d2d585..b3c90d5b1c72 100644 --- a/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/TestProject.csproj +++ b/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProject/TestProject.csproj @@ -8,5 +8,8 @@ + + + diff --git a/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProjectSolutionWithCodeCoverage.sln b/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProjectSolutionWithCodeCoverage.sln index 13471530b1e4..57a6d14e8d5c 100644 --- a/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProjectSolutionWithCodeCoverage.sln +++ b/test/TestAssets/TestProjects/TestProjectSolutionWithCodeCoverage/TestProjectSolutionWithCodeCoverage.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.13.35415.258 main MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject", "TestProject\TestProject.csproj", "{44DB7F03-7556-4EBA-BF32-C538B3A05742}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib", "Lib\Lib.csproj", "{DD629535-AE7F-4556-810F-A6AC6F69130B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {44DB7F03-7556-4EBA-BF32-C538B3A05742}.Debug|Any CPU.Build.0 = Debug|Any CPU {44DB7F03-7556-4EBA-BF32-C538B3A05742}.Release|Any CPU.ActiveCfg = Release|Any CPU {44DB7F03-7556-4EBA-BF32-C538B3A05742}.Release|Any CPU.Build.0 = Release|Any CPU + {DD629535-AE7F-4556-810F-A6AC6F69130B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD629535-AE7F-4556-810F-A6AC6F69130B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD629535-AE7F-4556-810F-A6AC6F69130B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD629535-AE7F-4556-810F-A6AC6F69130B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/UnitTests.proj b/test/UnitTests.proj index 06874d092d3f..2b59416df38c 100644 --- a/test/UnitTests.proj +++ b/test/UnitTests.proj @@ -11,7 +11,7 @@ $(AGENT_JOBNAME) run on (attempt $(SYSTEM_JOBATTEMPT)) - 02:00:00 + 01:00:00 @@ -203,6 +203,12 @@ call %HELIX_CORRELATION_PAYLOAD%\t\SetupHelixEnvironment.cmd $(TestFullMSBuild);$(HelixPreCommands) . $HELIX_CORRELATION_PAYLOAD/t/SetupHelixEnvironment.sh;$(HelixPreCommands) + + $(HelixPreCommands);%DOTNET_ROOT%\dotnet workload install wasm-tools --skip-manifest-update --configfile %TestExecutionDirectory%\NuGet.config + $(HelixPreCommands);$DOTNET_ROOT/dotnet workload install wasm-tools --skip-manifest-update --configfile $TestExecutionDirectory/NuGet.config PowerShell -ExecutionPolicy ByPass "dotnet nuget locals all -l | ForEach-Object { $_.Split(' ')[1]} | Where-Object{$_ -like '*cache'} | Get-ChildItem -Recurse -File -Filter '*.dat' | Measure";$(HelixPostCommands) PowerShell -ExecutionPolicy ByPass "Get-ChildItem -Recurse -File -Filter '*hangdump.dmp' | Copy-Item -Destination $env:HELIX_WORKITEM_UPLOAD_ROOT";$(HelixPostCommands) find "$HELIX_WORKITEM_UPLOAD_ROOT/../../.." -name '*hangdump.dmp' -print0 | xargs -0 -I@ cp @ "$HELIX_WORKITEM_UPLOAD_ROOT";$(HelixPostCommands) diff --git a/test/dotnet-aot.Tests/AotParserTests.cs b/test/dotnet-aot.Tests/AotParserTests.cs index a0ed5a5359af..fb51cb69cdd4 100644 --- a/test/dotnet-aot.Tests/AotParserTests.cs +++ b/test/dotnet-aot.Tests/AotParserTests.cs @@ -3,6 +3,7 @@ using System.CommandLine; using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.Extensions; using Microsoft.DotNet.Cli.Utils; using Microsoft.NET.TestFramework.Utilities; using Xunit; @@ -11,8 +12,10 @@ namespace Microsoft.DotNet.Cli.Tests; /// /// Tests for the AOT-compiled CLI parser (the #if CLI_AOT path in Parser.cs). -/// Validates that --version, --info, and default usage work correctly, -/// and that unsupported commands produce parse errors. +/// Validates that --version, --info, --help, and default usage are served entirely +/// from AOT, that the full command surface now parses (matching the managed CLI), +/// and that commands which require the managed CLI report this via +/// so the bridge can fall back. /// public class AotParserTests { @@ -38,17 +41,149 @@ public void ParseNoArgs_HasNoErrors() } [Fact] - public void ParseUnrecognizedCommand_HasErrors() + public void ParseKnownCommand_HasNoErrors() { + // The AOT parser now builds the full command tree, so real commands like `build` + // parse cleanly (they no longer surface as unknown). Execution still falls back. var result = Parser.Parse(["build"]); - Assert.NotEmpty(result.Errors); + Assert.Empty(result.Errors); + } + + [Fact] + public void DetectFileBasedApp_WhenFirstArgIsCSharpFile() + { + // `dotnet app.cs` is an implicit file-based app invocation. The AOT parser only sees the + // path as an unmatched root argument, so the shared detection (reused from the managed CLI) + // identifies it so NativeEntryPoint can defer to the managed run pipeline. + var csFile = Path.Combine(Path.GetTempPath(), $"aot-filebased-{Guid.NewGuid():N}.cs"); + File.WriteAllText(csFile, "Console.WriteLine(\"hi\");"); + try + { + var result = Parser.Parse([csFile]); + Assert.Empty(result.Errors); + Assert.NotNull(result.GetFileBasedAppEntryPointToken()); + } + finally + { + File.Delete(csFile); + } + } + + [Fact] + public void DoesNotDetectFileBasedApp_ForBuiltInCommand() + { + var result = Parser.Parse(["build"]); + Assert.Null(result.GetFileBasedAppEntryPointToken()); + } + + [Fact] + public void DoesNotDetectFileBasedApp_ForNonExistentFile() + { + // IsValidEntryPointPath requires the file to exist, so a bogus *.cs argument is not + // treated as a file-based app (it would resolve as an external `dotnet-` command). + var result = Parser.Parse([$"does-not-exist-{Guid.NewGuid():N}.cs"]); + Assert.Null(result.GetFileBasedAppEntryPointToken()); + } + + [Theory] + [InlineData("ef")] // external command: dotnet-ef + [InlineData("does-not-exist-command")] // unknown external command + public void DetectExternalCommand_RequiresManagedResolution(string command) + { + // `dotnet ` doesn't match a built-in command, so it lands on the root's hidden + // subcommand argument and must be deferred to the managed CLI's external command resolution + // rather than executed by the AOT root usage action. + var result = Parser.Parse([command]); + Assert.Empty(result.Errors); + Assert.True(result.RequiresManagedCommandResolution()); + } + + [Theory] + [InlineData("")] // `dotnet` (usage) + [InlineData("--version")] + [InlineData("--info")] + public void RootInvocations_DoNotRequireManagedResolution(string arg) + { + // Bare `dotnet`, `--version`, `--info`, etc. are handled entirely in AOT. + string[] args = arg.Length == 0 ? [] : [arg]; + var result = Parser.Parse(args); + Assert.False(result.RequiresManagedCommandResolution()); + } + + [Fact] + public void ParseHostHandledOption_HasNoErrors() + { + // --list-sdks / --list-runtimes are host-handled options defined on the root command + // so they appear in help and parse without error. The host resolves them before AOT. + Assert.Empty(Parser.Parse(["--list-sdks"]).Errors); + Assert.Empty(Parser.Parse(["--list-runtimes"]).Errors); } [Fact] - public void ParseUnrecognizedOption_HasErrors() + public void ParseUnknownToken_IsToleratedForExternalCommandForwarding() { - var result = Parser.Parse(["--list-sdks"]); - Assert.NotEmpty(result.Errors); + // The dotnet root command is intentionally tolerant of unknown tokens so that + // `dotnet foo` can be forwarded to an external `dotnet-foo` command. Unknown tokens + // therefore do not produce parse errors; they are resolved by the managed CLI on fallback. + var result = Parser.Parse(["--this-option-does-not-exist"]); + Assert.Empty(result.Errors); + } + + [Fact] + public void InvokeKnownCommand_FallsBackToManaged() + { + // Commands that cannot run in AOT must signal a managed fallback rather than execute. + var result = Parser.Parse(["build"]); + Assert.Empty(result.Errors); + Assert.Throws(() => Parser.Invoke(result)); + } + + [Fact] + public void InvokeRootHelp_RendersUsageFromAot() + { + var (exitCode, stdout, _) = InvokeWithCapture(["--help"]); + + Assert.Equal(0, exitCode); + Assert.Contains("dotnet", stdout); + Assert.Contains("build", stdout); + } + + [Fact] + public void InvokeCommandHelp_RendersFromAotWithoutFallback() + { + // Help for a definition-backed command (one that does not shell out to an external + // tool) renders entirely from AOT and must not request a managed fallback. + var result = Parser.Parse(["build", "--help"]); + var exception = Record.Exception(() => Parser.Invoke(result)); + + Assert.Null(exception); + } + + [Fact] + public void InvokeExternalToolHelp_RendersFromAotWithoutFallback() + { + // Help for the external-tool commands (msbuild/nuget/vstest/format/fsi) now shells out to the + // underlying tool from AOT instead of falling back to the managed CLI. The forwarded process + // may fail in the test environment, but help must never request a managed fallback. + var result = Parser.Parse(["msbuild", "--help"]); + var exception = Record.Exception(() => Parser.Invoke(result)); + + Assert.IsNotType(exception); + } + + [Fact] + public void InvokeCliSchema_RendersSchemaJsonFromAot() + { + // --cli-schema serializes the command tree via a source-generated JsonSerializerContext, + // so it runs entirely in AOT (no managed fallback) and emits the command surface as JSON. + var (exitCode, stdout, _) = InvokeWithCapture(["--cli-schema"]); + + Assert.Equal(0, exitCode); + // The root command name reflects the host executable, so assert on stable content instead: + // the SDK version, the subcommands collection, and a representative built-in subcommand. + Assert.Contains($"\"version\": \"{Product.Version}\"", stdout); + Assert.Contains("\"subcommands\"", stdout); + Assert.Contains("\"build\"", stdout); } [Fact] @@ -122,46 +257,49 @@ private static (int exitCode, string stdout, string stderr) InvokeWithCapture(st var bufferedOutput = new BufferedReporter(); var bufferedError = new BufferedReporter(); + var originalOut = Console.Out; + var originalErr = Console.Error; var stdoutWriter = new StringWriter(); var stderrWriter = new StringWriter(); - // Redirect InvocationConfiguration.Output/Error so S.CL writes are captured. - var originalInvocationOut = Parser.InvocationConfiguration.Output; - var originalInvocationErr = Parser.InvocationConfiguration.Error; - try { Reporter.SetOutput(bufferedOutput); Reporter.SetError(bufferedError); - Parser.InvocationConfiguration.Output = stdoutWriter; - Parser.InvocationConfiguration.Error = stderrWriter; - - int exitCode = Parser.Invoke(parseResult); + Console.SetOut(stdoutWriter); + Console.SetError(stderrWriter); + InvocationConfiguration invocationConfiguration = new() + { + EnableDefaultExceptionHandler = false, // parity with Parser.InvocationConfiguration + Output = stdoutWriter, + Error = stderrWriter + }; + int exitCode = parseResult.Invoke(invocationConfiguration); - // Combine Reporter output and InvocationConfiguration output + // Combine Reporter output and direct Console.Out output string reporterOut = string.Join(Environment.NewLine, bufferedOutput.Lines); - string invocationOut = stdoutWriter.ToString(); + string consoleOut = stdoutWriter.ToString(); string stdout = string.IsNullOrEmpty(reporterOut) - ? invocationOut - : (string.IsNullOrEmpty(invocationOut) + ? consoleOut + : (string.IsNullOrEmpty(consoleOut) ? reporterOut - : reporterOut + Environment.NewLine + invocationOut); + : reporterOut + Environment.NewLine + consoleOut); string reporterErr = string.Join(Environment.NewLine, bufferedError.Lines); - string invocationErr = stderrWriter.ToString(); + string consoleErr = stderrWriter.ToString(); string stderr = string.IsNullOrEmpty(reporterErr) - ? invocationErr - : (string.IsNullOrEmpty(invocationErr) + ? consoleErr + : (string.IsNullOrEmpty(consoleErr) ? reporterErr - : reporterErr + Environment.NewLine + invocationErr); + : reporterErr + Environment.NewLine + consoleErr); return (exitCode, stdout, stderr); } finally { Reporter.Reset(); - Parser.InvocationConfiguration.Output = originalInvocationOut; - Parser.InvocationConfiguration.Error = originalInvocationErr; + Console.SetOut(originalOut); + Console.SetError(originalErr); } } } diff --git a/test/dotnet-aot.Tests/NativeEntryPointTests.cs b/test/dotnet-aot.Tests/NativeEntryPointTests.cs index cd484b535c80..958740f7c24f 100644 --- a/test/dotnet-aot.Tests/NativeEntryPointTests.cs +++ b/test/dotnet-aot.Tests/NativeEntryPointTests.cs @@ -1,7 +1,10 @@ // 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 Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.Telemetry; +using Microsoft.DotNet.Cli.Utils; using Xunit; namespace Microsoft.DotNet.Cli.Tests; @@ -15,7 +18,7 @@ namespace Microsoft.DotNet.Cli.Tests; public class NativeEntryPointTests { /// - /// Runs a test action with DOTNET_CLI_ENABLEAOT and HOSTFXR_PATH restored afterward. + /// Runs a test action with relevant environment variables restored afterward. /// The xUnit v3 AOT source generator does not support IDisposable on test classes, /// so we use a helper with try/finally instead. /// @@ -23,6 +26,9 @@ private static void WithEnvRestore(Action action) { string? originalEnableAot = Environment.GetEnvironmentVariable("DOTNET_CLI_ENABLEAOT"); object? originalHostfxrPath = AppContext.GetData("HOSTFXR_PATH"); + string? originalTraceParent = Environment.GetEnvironmentVariable(Activities.TRACEPARENT); + string? originalTraceState = Environment.GetEnvironmentVariable(Activities.TRACESTATE); + string? originalTelemetryOptout = Environment.GetEnvironmentVariable("DOTNET_CLI_TELEMETRY_OPTOUT"); try { action(); @@ -31,6 +37,9 @@ private static void WithEnvRestore(Action action) { Environment.SetEnvironmentVariable("DOTNET_CLI_ENABLEAOT", originalEnableAot); AppContext.SetData("HOSTFXR_PATH", originalHostfxrPath); + Environment.SetEnvironmentVariable(Activities.TRACEPARENT, originalTraceParent); + Environment.SetEnvironmentVariable(Activities.TRACESTATE, originalTraceState); + Environment.SetEnvironmentVariable("DOTNET_CLI_TELEMETRY_OPTOUT", originalTelemetryOptout); } } @@ -218,6 +227,43 @@ public void ExecuteCore_AotEnabled_UnsupportedCommand_NoAotErrorLeaked() }); } + [Fact] + public void ExecuteCore_AotEnabled_FileBasedApp_FallsBackToManaged() + { + WithEnvRestore(() => + { + Environment.SetEnvironmentVariable("DOTNET_CLI_ENABLEAOT", "true"); + + // `dotnet app.cs` must not be served by the AOT path (which would print root usage); + // it has to fall back to the managed CLI's run pipeline. With a nonexistent SDK dir the + // fallback can't be hosted, so it reports the missing dotnet.dll - proving we reached it. + var csFile = Path.Combine(Path.GetTempPath(), $"aot-entry-filebased-{Guid.NewGuid():N}.cs"); + File.WriteAllText(csFile, "Console.WriteLine(\"hi\");"); + + var originalErr = Console.Error; + var stderrWriter = new StringWriter(); + Console.SetError(stderrWriter); + + try + { + int exitCode = NativeEntryPoint.ExecuteCore( + hostPath: "test-host", + dotnetRoot: "test-root", + sdkDir: "nonexistent-sdk-dir", + hostfxrPath: "", + args: [csFile]); + + Assert.Equal(1, exitCode); + Assert.Contains("dotnet.dll", stderrWriter.ToString()); + } + finally + { + Console.SetError(originalErr); + File.Delete(csFile); + } + }); + } + [Fact] public void ExecuteCore_SetsHostfxrPathInAppContext() { @@ -256,4 +302,67 @@ public void ExecuteCore_EmptyHostfxrPath_DoesNotSetAppContext() Assert.Null(AppContext.GetData("HOSTFXR_PATH")); }); } + + [Fact] + public void ExecuteCore_AotFastPath_CreatesMainActivity() + { + WithEnvRestore(() => + { + Environment.SetEnvironmentVariable("DOTNET_CLI_ENABLEAOT", "true"); + Environment.SetEnvironmentVariable("DOTNET_CLI_TELEMETRY_OPTOUT", "false"); + + var collectedActivities = new List(); + using var listener = new ActivityListener + { + ShouldListenTo = source => source.Name == "dotnet-cli", + Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.AllDataAndRecorded, + ActivityStopped = activity => collectedActivities.Add(activity), + }; + ActivitySource.AddActivityListener(listener); + + NativeEntryPoint.ExecuteCore( + hostPath: "test-host", + dotnetRoot: "test-root", + sdkDir: "nonexistent-sdk-dir", + hostfxrPath: "", + args: ["--version"]); + + var mainActivity = collectedActivities.FirstOrDefault(a => a.OperationName == "native-entrypoint"); + Assert.NotNull(mainActivity); + Assert.Equal(0, mainActivity.GetTagItem("process.exit.code")); + Assert.Equal(ActivityStatusCode.Ok, mainActivity.Status); + }); + } + + + [Fact] + public void ExecuteCore_TelemetryOptedOut_NoActivities() + { + WithEnvRestore(() => + { + Environment.SetEnvironmentVariable("DOTNET_CLI_ENABLEAOT", "true"); + Environment.SetEnvironmentVariable("DOTNET_CLI_TELEMETRY_OPTOUT", "true"); + + var collectedActivities = new List(); + using var listener = new ActivityListener + { + ShouldListenTo = source => source.Name == "dotnet-cli", + Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.AllDataAndRecorded, + ActivityStopped = activity => collectedActivities.Add(activity), + }; + ActivitySource.AddActivityListener(listener); + + NativeEntryPoint.ExecuteCore( + hostPath: "test-host", + dotnetRoot: "test-root", + sdkDir: "nonexistent-sdk-dir", + hostfxrPath: "", + args: ["--version"]); + + // The listener still collects activities because it's registered directly, + // but the TracerProvider is not built so AOT telemetry-specific behavior + // (like OTLP export) is skipped. The command should still succeed. + // Note: Activities may still be created because our test listener samples them. + }); + } } diff --git a/test/dotnet-aot.Tests/dotnet-aot.Tests.csproj b/test/dotnet-aot.Tests/dotnet-aot.Tests.csproj index b087adcf3c8f..a580340bbbcb 100644 --- a/test/dotnet-aot.Tests/dotnet-aot.Tests.csproj +++ b/test/dotnet-aot.Tests/dotnet-aot.Tests.csproj @@ -5,6 +5,7 @@ true $(DefineConstants);CLI_AOT Microsoft.DotNet.Cli.Tests + MicrosoftAspNetCore $(NoWarn);CS8002 @@ -31,7 +32,7 @@ false - + @@ -47,20 +48,22 @@ + + - - - + + + + - - + + +