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)