diff --git a/Directory.Build.props b/Directory.Build.props
index 9fe222dc98..0f9ee24cc2 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -22,6 +22,12 @@
diagnostics
+
+
+ $(MSBuildThisFileDirectory)eng/TraversalOverrides.targets
+
+
8.0
net$(NetCoreAppMinVersion)
+
+ 10.0
+ net$(NetCoreAppTestVersion)
net8.0;net9.0;net10.0;net11.0
- net8.0
+ $(NetCoreAppTestTargetFramework)
diff --git a/diagnostics.yml b/diagnostics.yml
index 343d9e85e5..ded5f372e1 100644
--- a/diagnostics.yml
+++ b/diagnostics.yml
@@ -52,7 +52,7 @@ extends:
parameters:
stages:
- stage: build
- displayName: Build and Test Diagnostics
+ displayName: Build Diagnostics
jobs:
############################
@@ -79,10 +79,12 @@ extends:
jobTemplate: ${{ variables.jobTemplate }}
name: Windows
osGroup: Windows_NT
- buildOnly: ${{ parameters.buildOnly }}
+ buildOnly: true
+ publishTestArtifacts: true
buildConfigs:
- configuration: Debug
architecture: x64
+ artifactUploadPath: bin/Windows_NT.x64.Debug
- configuration: Release
architecture: x64
artifactUploadPath: bin
@@ -101,6 +103,7 @@ extends:
container: linux_x64
crossBuild: true
buildOnly: true
+ publishTestArtifacts: true
buildConfigs:
- configuration: Release
architecture: x64
@@ -119,6 +122,7 @@ extends:
container: linux_musl_x64
crossBuild: true
buildOnly: true
+ publishTestArtifacts: true
buildConfigs:
- configuration: Release
architecture: x64
@@ -134,7 +138,8 @@ extends:
parameters:
jobTemplate: ${{ variables.jobTemplate }}
osGroup: MacOS
- buildOnly: ${{ parameters.buildOnly }}
+ buildOnly: true
+ publishTestArtifacts: true
buildConfigs:
- configuration: Release
architecture: x64
@@ -142,6 +147,7 @@ extends:
- ${{ if in(variables['Build.Reason'], 'PullRequest') }}:
- configuration: Debug
architecture: x64
+ artifactUploadPath: bin/osx.x64.Debug
- template: /eng/pipelines/build.yml
parameters:
@@ -212,13 +218,47 @@ extends:
artifactUploadPath: bin/linux.arm64.Release
artifactTargetPath: bin/linux-musl.arm64.Release
- ############################
- # #
- # Test only legs #
- # #
- ############################
+ ############################
+ # #
+ # Test stage #
+ # #
+ ############################
+
+ - ${{ if ne(parameters.buildOnly, true) }}:
+ - stage: test
+ displayName: Test Diagnostics
+ dependsOn: build
+ jobs:
+
+ - template: /eng/pipelines/build.yml
+ parameters:
+ jobTemplate: ${{ variables.jobTemplate }}
+ name: Windows_Test
+ osGroup: Windows_NT
+ dependsOn: Windows
+ testOnly: true
+ buildConfigs:
+ - configuration: Debug
+ architecture: x64
+ - configuration: Release
+ architecture: x64
+ - configuration: Release
+ architecture: x86
+
+ - template: /eng/pipelines/build.yml
+ parameters:
+ jobTemplate: ${{ variables.jobTemplate }}
+ name: MacOS_Test
+ osGroup: MacOS
+ dependsOn: MacOS
+ testOnly: true
+ buildConfigs:
+ - configuration: Release
+ architecture: x64
+ - ${{ if in(variables['Build.Reason'], 'PullRequest') }}:
+ - configuration: Debug
+ architecture: x64
- - ${{ if ne(parameters.buildOnly, true) }}:
- template: /eng/pipelines/build.yml
parameters:
jobTemplate: ${{ variables.jobTemplate }}
@@ -267,9 +307,16 @@ extends:
# - configuration: Debug
# architecture: x64
+ ############################
+ # #
+ # Package stage #
+ # #
+ ############################
+
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- stage: package
displayName: Package, Sign, and Generate BAR Manifests
+ dependsOn: build
jobs:
- template: /eng/common/templates-official/job/job.yml
parameters:
diff --git a/eng/AuxMsbuildFiles/SdkPackOverrides.targets b/eng/AuxMsbuildFiles/SdkPackOverrides.targets
index a2c3023663..94e01592e9 100644
--- a/eng/AuxMsbuildFiles/SdkPackOverrides.targets
+++ b/eng/AuxMsbuildFiles/SdkPackOverrides.targets
@@ -13,7 +13,7 @@
@(RuntimeTestVersions->WithMetadataValue('TargetFramework', 'net11.0')->Metadata('AspNet'))
-
+
diff --git a/eng/TraversalOverrides.targets b/eng/TraversalOverrides.targets
new file mode 100644
index 0000000000..684b964d4d
--- /dev/null
+++ b/eng/TraversalOverrides.targets
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
diff --git a/eng/build.ps1 b/eng/build.ps1
index 975097c9a6..0f64647493 100644
--- a/eng/build.ps1
+++ b/eng/build.ps1
@@ -124,8 +124,31 @@ if ($test) {
$testFilterArg = "/p:TestRunnerAdditionalArguments=\`"-class $classfilter\`""
}
+ # When the managed build was skipped (e.g. the test-only CI legs that download prebuilt
+ # product binaries), the debuggees built by BuildDebuggees in src/tests/dirs.proj were
+ # downloaded as part of TestArtifacts. Skip rebuilding them so this leg only runs tests.
+ # Test runtimes are still installed locally below (cheap, ensures correct file permissions).
+ $skipTestArtifactsBuild = if ($skipmanaged) { 'true' } else { 'false' }
+
+ # The managed build normally installs the test SDK/runtimes via an InstallRuntimes.proj
+ # ProjectReference. The -test step runs with Build=false, so install them explicitly here.
+ if ($skipmanaged) {
+ & "$engroot\common\build.ps1" `
+ -restore -build `
+ -projects "$engroot\InstallRuntimes.proj" `
+ -configuration $configuration `
+ -verbosity $verbosity `
+ -ci:$ci `
+ /p:TargetOS=$os `
+ /p:TargetArch=$architecture
+ if ($lastExitCode -ne 0) {
+ exit $lastExitCode
+ }
+ }
+
& "$engroot\common\build.ps1" `
-test `
+ -restore:$skipmanaged `
-configuration $configuration `
-verbosity $verbosity `
-ci:$ci `
@@ -133,6 +156,7 @@ if ($test) {
/p:TargetOS=$os `
/p:TargetArch=$architecture `
/p:TestArchitectures=$architecture `
+ /p:SkipTestArtifactsBuild=$skipTestArtifactsBuild `
/p:DotnetRuntimeVersion="$dotnetruntimeversion" `
/p:DotnetRuntimeDownloadVersion="$dotnetruntimedownloadversion" `
/p:RuntimeSourceFeed="$runtimesourcefeed" `
diff --git a/eng/build.sh b/eng/build.sh
index 1320b0a723..76a5874586 100755
--- a/eng/build.sh
+++ b/eng/build.sh
@@ -353,13 +353,39 @@ if [[ "$__Test" == 1 ]]; then
__TestFilterArg="/p:TestRunnerAdditionalArguments=\"$__TestFilter\""
fi
+ # When the managed build was skipped (e.g. the test-only CI legs that download prebuilt
+ # product binaries), the debuggees built by BuildDebuggees in src/tests/dirs.proj were
+ # downloaded as part of TestArtifacts. Skip rebuilding them so this leg only runs tests.
+ # Test runtimes are still installed locally below (cheap, ensures correct file permissions).
+ __TestRestoreArg=
+ __SkipTestArtifactsBuild=false
+ if [[ "$__ManagedBuild" == 0 ]]; then
+ __TestRestoreArg=--restore
+ __SkipTestArtifactsBuild=true
+
+ # The managed build normally installs the test SDK/runtimes via an InstallRuntimes.proj
+ # ProjectReference. The --test step runs with Build=false, so install them explicitly here.
+ "$__RepoRootDir/eng/common/build.sh" \
+ --restore --build \
+ --projects "$__RepoRootDir/eng/InstallRuntimes.proj" \
+ --configuration "$__BuildType" \
+ /p:TargetArch="$__TargetArch" \
+ /p:TargetRid="$__TargetRid" \
+ $__CommonMSBuildArgs
+ if [ $? != 0 ]; then
+ exit 1
+ fi
+ fi
+
# __CommonMSBuildArgs contains TargetOS property
"$__RepoRootDir/eng/common/build.sh" \
--test \
+ $__TestRestoreArg \
--configuration "$__BuildType" \
/bl:"$__LogsDir"/Test.binlog \
/p:TargetArch="$__TargetArch" \
/p:TargetRid="$__TargetRid" \
+ /p:SkipTestArtifactsBuild="$__SkipTestArtifactsBuild" \
/p:DotnetRuntimeVersion="$__DotnetRuntimeVersion" \
/p:DotnetRuntimeDownloadVersion="$__DotnetRuntimeDownloadVersion" \
/p:RuntimeSourceFeed="$__RuntimeSourceFeed" \
diff --git a/eng/pipelines/build.yml b/eng/pipelines/build.yml
index 058d36f3f7..d6b95a98ad 100644
--- a/eng/pipelines/build.yml
+++ b/eng/pipelines/build.yml
@@ -60,6 +60,12 @@ parameters:
type: boolean
default: false
+ # Optional: publish the full build outputs (managed + native + debuggees) as a
+ # 'TestArtifacts_' artifact so the matching test-only legs can run without rebuilding.
+- name: publishTestArtifacts
+ type: boolean
+ default: false
+
# Optional: architecture cross build if true
- name: crossBuild
type: boolean
@@ -113,7 +119,7 @@ jobs:
${{ if ne(parameters.strategy, '') }}:
'error, we can no longer support the strategy feature in the new pipeline system. Please remove the strategy from the job template.': error
- ${{ if ne(parameters.dependsOn, '') }}:
+ ${{ if and(ne(parameters.dependsOn, ''), ne(parameters.testOnly, true)) }}:
dependsOn: ${{ parameters.dependsOn }}_${{ config.architecture }}_${{ config.configuration }}
workspace:
@@ -128,16 +134,24 @@ jobs:
- _TestArgs: '-test'
- _Cross: ''
- - ${{ if eq(parameters.osGroup, 'Windows_NT') }}:
- - _buildScript: $(Build.SourcesDirectory)\build.cmd
- - ${{ if ne(parameters.osGroup, 'Windows_NT') }}:
- - _buildScript: $(Build.SourcesDirectory)/build.sh
-
- ${{ if and(eq(parameters.testOnly, 'true'), eq(parameters.buildOnly, 'true')) }}:
'error, testOnly and buildOnly cannot be true at the same time': error
+ # Test-only legs invoke test.cmd/test.sh, which already encode
+ # '-test -skipmanaged -skipnative' and do not prepend '-restore -build'. All other legs
+ # (build-only and build+test) use build.cmd/build.sh, which prepend '-restore -build'.
- ${{ if eq(parameters.testOnly, 'true') }}:
- - _TestArgs: '-test -skipnative'
+ - ${{ if eq(parameters.osGroup, 'Windows_NT') }}:
+ - _buildScript: $(Build.SourcesDirectory)\test.cmd
+ - ${{ if ne(parameters.osGroup, 'Windows_NT') }}:
+ - _buildScript: $(Build.SourcesDirectory)/test.sh
+ - _TestArgs: ''
+
+ - ${{ if ne(parameters.testOnly, 'true') }}:
+ - ${{ if eq(parameters.osGroup, 'Windows_NT') }}:
+ - _buildScript: $(Build.SourcesDirectory)\build.cmd
+ - ${{ if ne(parameters.osGroup, 'Windows_NT') }}:
+ - _buildScript: $(Build.SourcesDirectory)/build.sh
- ${{ if eq(parameters.buildOnly, 'true') }}:
- _TestArgs: ''
@@ -157,19 +171,18 @@ jobs:
steps:
- ${{ if eq(parameters.testOnly, true) }}:
- - ${{ if ne(parameters.osGroup, 'Linux') }}:
- - 'error, testOnly is only supported on Linux': error
+ - ${{ if notIn(parameters.osGroup, 'Windows_NT', 'MacOS', 'Linux') }}:
+ - 'error, testOnly is only supported on Windows_NT, MacOS, and Linux': error
+ # The matching build leg published its full outputs (managed assemblies, native
+ # binaries, and debuggees) as TestArtifacts_. Restore them into the repo
+ # artifacts directory so the test run can skip both the native and managed builds
+ # (-skipnative -skipmanaged) and only execute the tests.
- task: DownloadPipelineArtifact@2
displayName: 'Download Build Artifacts'
inputs:
- targetPath: '$(Build.ArtifactStagingDirectory)/__download__'
- itemPattern: Build_${{ parameters.dependsOn }}_${{ config.architecture }}_${{ config.configuration }}/bin/**
+ artifact: TestArtifacts_${{ parameters.dependsOn }}_${{ config.architecture }}_${{ config.configuration }}
+ targetPath: '$(Build.SourcesDirectory)/artifacts'
checkDownloadedFiles: true
- - task: CopyFiles@2
- displayName: 'Binplace Downloaded Product'
- inputs:
- sourceFolder: $(Build.ArtifactStagingDirectory)/__download__/Build_${{ parameters.dependsOn }}_${{ config.architecture }}_${{ config.configuration }}/bin/linux${{ parameters.osSuffix }}.${{ config.architecture }}.${{ config.configuration }}
- targetFolder: '$(Build.SourcesDirectory)/artifacts/bin/linux.${{ config.architecture }}.${{ config.configuration }}'
- script: $(_buildScript)
-ci
@@ -202,6 +215,27 @@ jobs:
targetPath: '$(Build.ArtifactStagingDirectory)/artifacts'
artifactName: Build_$(_PhaseName)
+ # Publish the full build outputs for the matching test-only legs to consume. This lets the
+ # test legs run with -skipnative -skipmanaged instead of rebuilding the product themselves.
+ # Only valid on build-only legs (publishTestArtifacts without buildOnly is a configuration error).
+ - ${{ if and(eq(parameters.publishTestArtifacts, true), eq(parameters.buildOnly, true)) }}:
+ - task: CopyFiles@2
+ displayName: Gather test artifacts for publish
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)/artifacts'
+ Contents: |
+ bin/**
+ obj/**
+ test/**
+ TargetFolder: $(Build.ArtifactStagingDirectory)/testartifacts
+
+ - template: /eng/pipelines/publish-pipeline-artifact-shim.yml@self
+ parameters:
+ displayName: Publish Test Artifacts
+ inputs:
+ targetPath: '$(Build.ArtifactStagingDirectory)/testartifacts'
+ artifactName: TestArtifacts_$(_PhaseName)
+
- ${{ if ne(parameters.buildOnly, 'true') }}:
# Publish test results to Azure Pipelines
- task: PublishTestResults@2
diff --git a/global.json b/global.json
index 75792e25d1..979ba15a3a 100644
--- a/global.json
+++ b/global.json
@@ -7,11 +7,8 @@
"tools": {
"dotnet": "10.0.108",
"runtimes": {
- "dotnet": [
- "$(MicrosoftNETCoreApp80Version)"
- ],
"dotnet/x86": [
- "$(MicrosoftNETCoreApp80Version)"
+ "$(MicrosoftNETCoreApp100Version)"
]
}
},
diff --git a/src/tests/DbgShim.UnitTests/DbgShim.UnitTests.csproj b/src/tests/DbgShim.UnitTests/DbgShim.UnitTests.csproj
index c931e79852..3b9c84c185 100644
--- a/src/tests/DbgShim.UnitTests/DbgShim.UnitTests.csproj
+++ b/src/tests/DbgShim.UnitTests/DbgShim.UnitTests.csproj
@@ -1,7 +1,7 @@
- $(NetCoreAppMinTargetFramework)
+ $(NetCoreAppTestTargetFramework)
true
$(OutputPath)$(TargetFramework)\Debugger.Tests.Common.txt
1.0.351101
diff --git a/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/Microsoft.Diagnostics.DebugServices.UnitTests.csproj b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/Microsoft.Diagnostics.DebugServices.UnitTests.csproj
index 9a4014149c..e71b2f7d7f 100644
--- a/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/Microsoft.Diagnostics.DebugServices.UnitTests.csproj
+++ b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/Microsoft.Diagnostics.DebugServices.UnitTests.csproj
@@ -1,7 +1,7 @@
- $(NetCoreAppMinTargetFramework)
+ $(NetCoreAppTestTargetFramework)
$(OutputPath)$(TargetFramework)\Debugger.Tests.Common.txt
1.0.351101
diff --git a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs
index c8ed1e4f24..1b1d00e0e8 100644
--- a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs
+++ b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs
@@ -62,7 +62,7 @@ public async Task TestLogsAllCategoriesAllLevels(TestConfiguration config)
ValidateAppLoggerCategoryWarningMessage(reader);
ValidateAppLoggerCategoryErrorMessage(reader);
- Assert.True(reader.EndOfStream, "Expected to have read all entries from stream.");
+ Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream.");
}
///
@@ -84,7 +84,7 @@ public async Task TestLogsAllCategoriesDefaultLevel(TestConfiguration config)
ValidateAppLoggerCategoryWarningMessage(reader);
ValidateAppLoggerCategoryErrorMessage(reader);
- Assert.True(reader.EndOfStream, "Expected to have read all entries from stream.");
+ Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream.");
}
///
@@ -116,7 +116,7 @@ public async Task TestLogsAllCategoriesDefaultLevelFallback(TestConfiguration co
ValidateLoggerRemoteCategoryWarningMessage(reader);
ValidateAppLoggerCategoryErrorMessage(reader);
- Assert.True(reader.EndOfStream, "Expected to have read all entries from stream.");
+ Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream.");
}
///
@@ -157,7 +157,7 @@ public async Task TestLogsUseAppFilters(TestConfiguration config)
ValidateAppLoggerCategoryWarningMessage(reader);
ValidateAppLoggerCategoryErrorMessage(reader);
- Assert.True(reader.EndOfStream, "Expected to have read all entries from stream.");
+ Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream.");
}
///
@@ -182,7 +182,7 @@ public async Task TestLogsUseAppFiltersAndFilterSpecs(TestConfiguration config)
ValidateAppLoggerCategoryWarningMessage(reader);
ValidateAppLoggerCategoryErrorMessage(reader);
- Assert.True(reader.EndOfStream, "Expected to have read all entries from stream.");
+ Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream.");
}
///
@@ -213,7 +213,7 @@ public async Task TestLogsWildcardCategory(TestConfiguration config)
ValidateAppLoggerCategoryWarningMessage(reader);
ValidateAppLoggerCategoryErrorMessage(reader);
- Assert.True(reader.EndOfStream, "Expected to have read all entries from stream.");
+ Assert.True(string.IsNullOrEmpty(await reader.ReadToEndAsync()), "Expected to have read all entries from stream.");
}
private async Task GetLogsAsync(TestConfiguration config, Action settingsCallback = null)
diff --git a/src/tests/Microsoft.FileFormats.UnitTests/Microsoft.FileFormats.UnitTests.csproj b/src/tests/Microsoft.FileFormats.UnitTests/Microsoft.FileFormats.UnitTests.csproj
index 808617aa05..513ca6baa5 100644
--- a/src/tests/Microsoft.FileFormats.UnitTests/Microsoft.FileFormats.UnitTests.csproj
+++ b/src/tests/Microsoft.FileFormats.UnitTests/Microsoft.FileFormats.UnitTests.csproj
@@ -1,6 +1,6 @@
- $(NetCoreAppMinTargetFramework)
+ $(NetCoreAppTestTargetFramework)
;1591;1701
diff --git a/src/tests/Microsoft.SymbolStore.UnitTests/Microsoft.SymbolStore.UnitTests.csproj b/src/tests/Microsoft.SymbolStore.UnitTests/Microsoft.SymbolStore.UnitTests.csproj
index e2dc9e42a7..3805aa1334 100644
--- a/src/tests/Microsoft.SymbolStore.UnitTests/Microsoft.SymbolStore.UnitTests.csproj
+++ b/src/tests/Microsoft.SymbolStore.UnitTests/Microsoft.SymbolStore.UnitTests.csproj
@@ -1,6 +1,6 @@
- $(NetCoreAppMinTargetFramework)
+ $(NetCoreAppTestTargetFramework)
;1591;1701
diff --git a/src/tests/SOS.UnitTests/Debuggees/Directory.Build.targets b/src/tests/SOS.UnitTests/Debuggees/Directory.Build.targets
index 309df60cdd..3671dfe974 100644
--- a/src/tests/SOS.UnitTests/Debuggees/Directory.Build.targets
+++ b/src/tests/SOS.UnitTests/Debuggees/Directory.Build.targets
@@ -40,8 +40,7 @@
-
+
diff --git a/src/tests/SOS.UnitTests/SOS.UnitTests.csproj b/src/tests/SOS.UnitTests/SOS.UnitTests.csproj
index d2f3b4cbb7..df9a23e046 100644
--- a/src/tests/SOS.UnitTests/SOS.UnitTests.csproj
+++ b/src/tests/SOS.UnitTests/SOS.UnitTests.csproj
@@ -1,6 +1,6 @@
- $(NetCoreAppMinTargetFramework)
+ $(NetCoreAppTestTargetFramework)
false
;1591;1701
$(DefineConstants);CORE_CLR
diff --git a/src/tests/dirs.proj b/src/tests/dirs.proj
index c57f908ddc..a37899c9ce 100644
--- a/src/tests/dirs.proj
+++ b/src/tests/dirs.proj
@@ -16,7 +16,9 @@
+ result cache, even when multiple test projects depend on it.
+ Test-only legs install runtimes locally too (cheap, gets correct file perms)
+ and only skip the expensive debuggee rebuild via $(SkipTestArtifactsBuild). -->
@@ -39,7 +41,7 @@
+ Condition="'$(SkipTests)' != 'true' and '$(SkipTestArtifactsBuild)' != 'true'">
diff --git a/src/tests/dotnet-counters/DotnetCounters.UnitTests.csproj b/src/tests/dotnet-counters/DotnetCounters.UnitTests.csproj
index aa872e9b45..6472bcfb65 100644
--- a/src/tests/dotnet-counters/DotnetCounters.UnitTests.csproj
+++ b/src/tests/dotnet-counters/DotnetCounters.UnitTests.csproj
@@ -1,7 +1,7 @@
- $(NetCoreAppMinTargetFramework)
+ $(NetCoreAppTestTargetFramework)
diff --git a/src/tests/dotnet-trace/DotnetTrace.UnitTests.csproj b/src/tests/dotnet-trace/DotnetTrace.UnitTests.csproj
index 9d70543023..056dd23295 100644
--- a/src/tests/dotnet-trace/DotnetTrace.UnitTests.csproj
+++ b/src/tests/dotnet-trace/DotnetTrace.UnitTests.csproj
@@ -1,7 +1,7 @@
- $(NetCoreAppMinTargetFramework)
+ $(NetCoreAppTestTargetFramework)