diff options
-rw-r--r-- | NuGet.Config | 9 | ||||
-rw-r--r-- | azure-pipelines.yml | 178 | ||||
-rw-r--r-- | build-test.cmd | 2 | ||||
-rw-r--r-- | dir.common.props | 4 | ||||
-rw-r--r-- | eng/build-job.yml | 108 | ||||
-rw-r--r-- | eng/install-native-dependencies.sh | 25 | ||||
-rw-r--r-- | eng/kill_tasks.cmd | 10 | ||||
-rw-r--r-- | eng/platform-matrix.yml | 61 | ||||
-rw-r--r-- | eng/test-job.yml | 121 | ||||
-rw-r--r-- | eng/xplat-job.yml | 50 | ||||
-rw-r--r-- | src/pal/tools/probe-win.ps1 | 2 | ||||
-rw-r--r-- | src/publishwitharcade.proj | 37 | ||||
-rw-r--r-- | src/restorearcadepublishtasks.proj | 16 | ||||
-rw-r--r-- | tests/helixprep.proj | 39 | ||||
-rw-r--r-- | tests/helixpublishwitharcade.proj | 93 | ||||
-rwxr-xr-x | tests/runtest_helix.py | 104 |
16 files changed, 846 insertions, 13 deletions
diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000000..7fa789a1df --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <packageSources> + <clear /> + <add key="arcade" value="https://dotnetfeed.blob.core.windows.net/dotnet-tools-internal/index.json" /> + <add key="dotnet-core" value="https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json" /> + <add key="nuget.org" value="https://api.nuget.org/v3/index.json" /> + </packageSources> +</configuration>
\ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000..5f6b4a49f4 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,178 @@ +resources: + repositories: + # shared library repository + - repository: arcade + type: github + endpoint: DotNet-Bot GitHub Connection + name: dotnet/arcade + ref: refs/heads/master + +variables: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + + +jobs: + +## The following is the matrix of test runs that we have. This is +## duplicated for each os/arch combination in platform-matrix.yml. + +## +## Product build Test build Test run +## (Azure DevOps) (Azure DevOps) (helix) +## +## ########################################################################################### +## +## Debug +## +## Checked ----------> Pri0 -----------------> plain runtests +## | +## \---------> Pri1 -----------------> plain runtests +## | \----------------> jitstress +## | \----------------> gcstress +## | \----------------> maybe more (dynamically selected runtest modes) +## | +## \---------> Pri1 crossgen --------> plain runtests +## \-------> jitstress +## \-------> gcstress +## \-------> maybe more (dynamically selected runtest modes) +## +## Release ----------> Pri1 -----------------> plain runtests +## | +## \---------> Pri1 crossgen --------> plain runtests +## +## + +## Each build or test job is defined in Azure DevOps, and will show +## up in the UI in the order in which they are defined here. The +## build and test build job matrix is defined statically, but +## queue-time inputs can be used to control whether a job executes +## (used to select which jobs run in ci vs for official builds), or +## to select test modes. This should eventually be used to enable +## requesting specific test runs from pull requests. + + +## +## Templates used to define jobs: +## Please update this if the factoring changes. +## +## This file defines the set of jobs in a platform-agnostic manner, +## using the platform-matrix.yml template. This will create one job +## for each platform from the passed-in jobTemplate (either a build +## job or a test job). The build-job.yml and test-job.yml templates +## use xplat-job.yml to handle some of the common logic for +## abstracting over platforms. Finally, xplat-job.yml uses the arcade +## base.yml job template, which sets up telemetry and signing support. + +## azure-pipelines.yml -> platform-matrix.yml -------> build-job.yml -------> xplat-job.yml -> base.yml +## | (passed-in jobTemplate) | (arcade) +## \------> test-job.yml ------/ + + + +# +# Debug build +# + +- template: eng/platform-matrix.yml + parameters: + jobTemplate: build-job.yml + buildConfig: debug + +# +# Checked build +# + +- template: eng/platform-matrix.yml + parameters: + jobTemplate: build-job.yml + buildConfig: checked + +# +# Release build +# + +- template: eng/platform-matrix.yml + parameters: + jobTemplate: build-job.yml + buildConfig: release + +# +# Checked test builds +# + +# Pri0 +- template: eng/platform-matrix.yml + parameters: + jobTemplate: test-job.yml + buildConfig: checked + jobParameters: + priority: 0 + +# Pri1 +- template: eng/platform-matrix.yml + parameters: + jobTemplate: test-job.yml + buildConfig: checked + jobParameters: + priority: 1 + scenarios: 'normal;jitstress2' + +# Pri1 crossgen +- template: eng/platform-matrix.yml + parameters: + jobTemplate: test-job.yml + buildConfig: checked + jobParameters: + priority: 1 + crossgen: true + scenarios: 'normal;jitstress2' + +# +# Release test builds +# + +# Pri1 +- template: eng/platform-matrix.yml + parameters: + jobTemplate: test-job.yml + buildConfig: release + jobParameters: + priority: 1 + +# Pri1 crossgen +- template: eng/platform-matrix.yml + parameters: + jobTemplate: test-job.yml + buildConfig: release + jobParameters: + priority: 1 + crossgen: true + + +# Publish build information to Build Assets Registry + +# This job gathers build assets from the pipeline (from each official +# product build job), and publishes them to the build assets +# registry. Its dependencies should be updated to include all of the +# official builds if we add more platform/arch combinations. + +# TODO: Enable publish to BAR +#- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: +# - template: /eng/common/templates/phases/publish-build-assets.yml@arcade +#- phase: publish_bar +# displayName: publish to BAR (empty currently) +# queue: +# name: Hosted VS2017 +# dependsOn: +# - build_Linux_x64_release +# - build_OSX_x64_release +# - build_Windows_NT_x64_release +# - build_Windows_NT_x86_release +# - build_Windows_NT_arm_release +# - build_Windows_NT_arm64_release + # TODO: enable these builds + # - build_rhel_x64_release + # - build_alpine_x64_release + # - build_crossbuild_arm_release + # - build_crossbuild_arm64_release + diff --git a/build-test.cmd b/build-test.cmd index 29bc779729..790b75fd3b 100644 --- a/build-test.cmd +++ b/build-test.cmd @@ -527,7 +527,7 @@ set __MsbuildWrn=/flp1:WarningsOnly;LogFile="%__BuildWrn%" set __MsbuildErr=/flp2:ErrorsOnly;LogFile="%__BuildErr%" set __Logging=-MsBuildLog=!__MsbuildLog! -MsBuildWrn=!__MsbuildWrn! -MsBuildErr=!__MsbuildErr! -call %__ProjectDir%\run.cmd build -Project=%__ProjectDir%\tests\helixprep.proj !__Logging! %__RunArgs% %__BuildAgainstPackagesArg% %RuntimeIdArg% %TargetsWindowsArg% %__CrossgenArg% %__PriorityArg% %__PassThroughArg% %__UnprocessedBuildArgs% +call %__ProjectDir%\run.cmd build -Project=%__ProjectDir%\tests\helixprep.proj !__Logging! %__RunArgs% %RuntimeIdArg% %TargetsWindowsArg% %__CrossgenArg% %__PriorityArg% %__PassThroughArg% %__UnprocessedBuildArgs% if errorlevel 1 ( echo %__MsgPrefix%Error: build failed. Refer to the build log files for details: echo %__BuildLog% diff --git a/dir.common.props b/dir.common.props index f94528972e..0c0096c9fb 100644 --- a/dir.common.props +++ b/dir.common.props @@ -22,7 +22,9 @@ <BuildType Condition="'$(__BuildType)' == 'checked'">Checked</BuildType> <BuildOS>$(__BuildOS)</BuildOS> - <BuildOS Condition="'$(__BuildOS)' == ''">Windows_NT</BuildOS> + <BuildOS Condition="'$(__BuildOS)' == '' And '$([MSBuild]::IsOSPlatform(Windows))' == 'true'">Windows_NT</BuildOS> + <BuildOS Condition="'$(__BuildOS)' == '' And '$([MSBuild]::IsOSPlatform(Linux))' == 'true'">Linux</BuildOS> + <BuildOS Condition="'$(__BuildOS)' == '' And '$([MSBuild]::IsOSPlatform(OSX))' == 'true'">OSX</BuildOS> <Configuration Condition="'$(Configuration)' == ''">$(BuildType)</Configuration> <Platform Condition="'$(Platform)' == ''">$(BuildArch)</Platform> diff --git a/eng/build-job.yml b/eng/build-job.yml new file mode 100644 index 0000000000..08f8ac0b95 --- /dev/null +++ b/eng/build-job.yml @@ -0,0 +1,108 @@ +parameters: + buildConfig: '' + archType: '' + osGroup: '' + +### Product build +jobs: +- template: xplat-job.yml + parameters: + buildConfig: ${{ parameters.buildConfig }} + archType: ${{ parameters.archType }} + osGroup: ${{ parameters.osGroup }} + + # Compute job name from template parameters + name: ${{ format('build_{0}_{1}_{2}', parameters.osGroup, parameters.archType, parameters.buildConfig) }} + displayName: ${{ format('Build {0} {1} {2}', parameters.osGroup, parameters.archType, parameters.buildConfig) }} + + steps: + + # Install native dependencies + - ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + - script: sh eng/install-native-dependencies.sh $(osGroup) + displayName: Install native dependencies + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + # Necessary to install python + - script: eng\common\init-tools-native.cmd -InstallDirectory $(Build.SourcesDirectory)\native-tools -Force + displayName: Install native dependencies + + + # Run init-tools (pre-arcade dependency bootstrapping) + # TODO: replace this with an arcade equivalent + - ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + - script: ./init-tools.sh + displayName: Init tools + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + - script: .\init-tools.cmd + displayName: Init tools + + + # Sync + - ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + - script: ./Tools/dotnetcli/dotnet msbuild build.proj /p:RestoreDuringBuild=true /t:Sync + displayName: Sync + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + - script: .\Tools\dotnetcli\dotnet.exe msbuild build.proj /p:RestoreDuringBuild=true /t:Sync + displayName: Sync + + + # Build + - ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + - script: ./build.sh $(buildConfig) $(archType) -skipnuget -skiprestore + displayName: Build product + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + # TODO: IBCOptimize? EnforcePGO? pass an OfficialBuildId? SignType? file logging parameters? + - script: set __TestIntermediateDir=int&&build.cmd $(buildConfig) $(archType) -skiptests -skipbuildpackages -skiprestore + displayName: Build product + + + # Upload build as pipeline artifact + - ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + - task: PublishPipelineArtifact@0 + displayName: Save product build as pipeline artifact + inputs: + artifactName: ${{ format('{0}_{1}_{2}_build', parameters.osGroup, parameters.archType, parameters.buildConfig) }} + targetPath: $(Build.SourcesDirectory)/bin/Product/$(osGroup).$(archType).$(buildConfigUpper) + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + - task: PublishPipelineArtifact@0 + displayName: Save product build as pipeline artifact + inputs: + artifactName: ${{ format('{0}_{1}_{2}_build', parameters.osGroup, parameters.archType, parameters.buildConfig) }} + targetPath: $(Build.SourcesDirectory)\bin\Product\Windows_NT.$(archType).$(buildConfigUpper) + + + # TODO: Sign + - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - script: echo Sign! + displayName: Sign Binaries (empty for now) + + + # Get key vault secrets for publishing + - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - task: AzureKeyVault@1 + inputs: + azureSubscription: 'DotNet-Engineering-Services_KeyVault' + KeyVaultName: EngKeyVault + SecretsFilter: 'dotnetfeed-storage-access-key-1,microsoft-symbol-server-pat,symweb-symbol-server-pat' + + + # TODO: Build packages and publish official build + #- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + # ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + # # TODO: ensure that NUGET_PACKAGES path is correctly set + # - script: .dotnet/dotnet msbuild src/restorearcadepublishtasks.proj /t:Restore + # displayName: Restore tasks used to publish the build + # - script: .dotnet/dotnet msbuild src/publishwitharcade.proj /t:PublishPackages /p:AzureFeedUrl=$(AzureFeedUrl) /p:AccountKey=$(AccountKey) + # displayName: Publish official build + # ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + # # TODO: pass publish feed url and access token in from the internal pipeline + # - script: .dotnet\dotnet.exe msbuild src\restorearcadepublishtasks.proj /t:Restore + # displayName: Restore tasks used to publish the build + # - script: .dotnet\dotnet.exe msbuild src\publishwitharcade.proj /t:PublishPackages /p:AzureFeedUrl=$(AzureFeedUrl) /p:AccountKey=$(AccountKey) + + # Kill tasks that hold onto files on Windows. Otherwise git clean + # may fail for later jobs on the same agent. + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + - script: eng/kill_tasks.cmd + displayName: Kill tasks that hold on to files + condition: always() diff --git a/eng/install-native-dependencies.sh b/eng/install-native-dependencies.sh new file mode 100644 index 0000000000..9e80c57dfc --- /dev/null +++ b/eng/install-native-dependencies.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env sh + +if [ "$1" = "Linux" ]; then + sudo apt update + if [ "$?" != "0" ]; then + exit 1; + fi + sudo apt install cmake llvm-3.9 clang-3.9 lldb-3.9 liblldb-3.9-dev libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev libcurl4-openssl-dev libssl-dev libkrb5-dev libnuma-dev + if [ "$?" != "0"]; then + exit 1; + fi +elif [ "$1" = "OSX" ]; then + brew install icu4c openssl + if [ "$?" != "0" ]; then + exit 1; + fi + brew link --force icu4c + if [ "$?" != "0"]; then + exit 1; + fi +else + echo "Must pass \"Linux\" or \"OSX\" as first argument." + exit 1 +fi + diff --git a/eng/kill_tasks.cmd b/eng/kill_tasks.cmd new file mode 100644 index 0000000000..ee7099c94d --- /dev/null +++ b/eng/kill_tasks.cmd @@ -0,0 +1,10 @@ +@if not defined _echo @echo off +setlocal EnableDelayedExpansion + +:: Check if VBCSCompiler.exe is running +tasklist /fi "imagename eq VBCSCompiler.exe" |find ":" > nul +:: Compiler is running if errorlevel == 1 +if errorlevel 1 ( + echo Stop VBCSCompiler.exe execution. + for /f "tokens=2 delims=," %%F in ('tasklist /nh /fi "imagename eq VBCSCompiler.exe" /fo csv') do taskkill /f /PID %%~F +) diff --git a/eng/platform-matrix.yml b/eng/platform-matrix.yml new file mode 100644 index 0000000000..7f1a463639 --- /dev/null +++ b/eng/platform-matrix.yml @@ -0,0 +1,61 @@ +parameters: + jobTemplate: '' + buildConfig: '' + jobParameters: {} + +jobs: + +# Linux x64 + +- template: ${{ parameters.jobTemplate }} + parameters: + buildConfig: ${{ parameters.buildConfig }} + archType: x64 + osGroup: Linux + ${{ insert }}: ${{ parameters.jobParameters }} + +# macOS x64 + +- template: ${{ parameters.jobTemplate }} + parameters: + buildConfig: ${{ parameters.buildConfig }} + archType: x64 + osGroup: OSX + ${{ insert }}: ${{ parameters.jobParameters }} + +# Windows x64/x86/arm/arm64 + +- template: ${{ parameters.jobTemplate }} + parameters: + buildConfig: ${{ parameters.buildConfig }} + archType: x64 + osGroup: Windows_NT + ${{ insert }}: ${{ parameters.jobParameters }} + +- template: ${{ parameters.jobTemplate }} + parameters: + buildConfig: ${{ parameters.buildConfig }} + archType: x86 + osGroup: Windows_NT + ${{ insert }}: ${{ parameters.jobParameters }} + +- template: ${{ parameters.jobTemplate }} + parameters: + buildConfig: ${{ parameters.buildConfig }} + archType: arm + osGroup: Windows_NT + ${{ insert }}: ${{ parameters.jobParameters }} + +- template: ${{ parameters.jobTemplate }} + parameters: + buildConfig: ${{ parameters.buildConfig }} + archType: arm64 + osGroup: Windows_NT + ${{ insert }}: ${{ parameters.jobParameters }} + +# TODO for official build: +# RedHat x64 +# Linux crossbuild arm +# Linux crossbuild arm64 +# Linux musl x64 + diff --git a/eng/test-job.yml b/eng/test-job.yml new file mode 100644 index 0000000000..0a1a9ebfb2 --- /dev/null +++ b/eng/test-job.yml @@ -0,0 +1,121 @@ +parameters: + buildConfig: '' + archType: '' + osGroup: '' + priority: 0 + crossgen: false + scenarios: '' + +### Test job + +### Each test job depends on a corresponding build job with the same +### buildConfig and archType. + +jobs: +- template: xplat-job.yml + parameters: + buildConfig: ${{ parameters.buildConfig }} + archType: ${{ parameters.archType }} + osGroup: ${{ parameters.osGroup }} + + # Compute job name from template parameters + ${{ if eq(parameters.crossgen, 'false') }}: + name: ${{ format('testbuild_pri{0}_{1}_{2}_{3}', parameters.priority, parameters.osGroup, parameters.archType, parameters.buildConfig) }} + displayName: ${{ format('Test pri{0} {1} {2} {3}', parameters.priority, parameters.osGroup, parameters.archType, parameters.buildConfig) }} + ${{ if eq(parameters.crossgen, 'true') }}: + name: ${{ format('testbuild_pri{0}_r2r_{1}_{2}_{3}', parameters.priority, parameters.osGroup, parameters.archType, parameters.buildConfig) }} + displayName: ${{ format('Test Pri{0} R2R {1} {2} {3}', parameters.priority, parameters.osGroup, parameters.archType, parameters.buildConfig) }} + + variables: + # Map template parameters to command line arguments + ${{ if eq(parameters.priority, '1') }}: + ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + priorityArg: 'priority1' + ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + priorityArg: '-priority=1' + ${{ if eq(parameters.priority, '0') }}: + priorityArg: '' + + ${{ if eq(parameters.crossgen, 'true') }}: + crossgenArg: 'crossgen' + ${{ if eq(parameters.crossgen, 'false') }}: + crossgenArg: '' + ${{ if ne(parameters.scenarios, '') }}: + scenariosArg: ${{ format('/p:"Scenarios={0}"', parameters.scenarios) }} + ${{ if eq(parameters.scenarios, '') }}: + scenariosArg: '' + + # TODO: Enable crossgen in build-test.sh. It currently doesn't + # accept a crossgen arg, so disable the macos/linux crossgen test + # build jobs. + ${{ if and(eq(parameters.crossgen, 'true'), or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX'))) }}: + condition: false + + # Test job depends on the corresponding build job + dependsOn: ${{ format('build_{0}_{1}_{2}', parameters.osGroup, parameters.archType, parameters.buildConfig) }} + + steps: + + # Install test build dependencies + - ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + - script: sh eng/install-native-dependencies.sh $(osGroup) + displayName: Install native dependencies + + + # Download product build from pipeline artifact storage + - ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + - task: DownloadPipelineArtifact@0 + displayName: Download product build pipeline artifact + inputs: + artifactName: ${{ format('{0}_{1}_{2}_build', parameters.osGroup, parameters.archType, parameters.buildConfig) }} + targetPath: $(Build.SourcesDirectory)/bin/Product/$(osGroup).$(archType).$(buildConfigUpper) + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + - task: DownloadPipelineArtifact@0 + displayName: Download product build pipeline artifact + inputs: + artifactName: ${{ format('{0}_{1}_{2}_build', parameters.osGroup, parameters.archType, parameters.buildConfig) }} + targetPath: $(Build.SourcesDirectory)\bin\Product\Windows_NT.$(archType).$(buildConfigUpper) + + + # Build tests + - ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + # TODO: enable crossgen in build-test.sh + - script: ./build-test.sh $(buildConfig) $(archType) $(priorityArg) $(crossgenArg) + displayName: Build tests + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + - script: build-test.cmd $(buildConfig) $(archType) $(priorityArg) $(crossgenArg) + displayName: Build tests + + + # Prepare tests for helix + - ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + - script: ./Tools/dotnetcli/dotnet msbuild tests/helixprep.proj /p:CORE_ROOT=$(Build.SourcesDirectory)/bin/tests/$(osGroup).$(archType).$(buildConfigUpper)/Tests/Core_Root /p:__BuildType=$(buildConfig) /p:__BuildArch=$(archType) /p:UsePython=true + # TODO: remove UsePython argument once we've removed generated wrappers in helixprep.proj + displayName: Prepare test archives for Helix + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + # TODO: remove UsePython argument once we've removed generated wrappers in helixprep.proj + - script: .\Tools\dotnetcli\dotnet.exe msbuild tests\helixprep.proj /p:CORE_ROOT=$(Build.SourcesDirectory)\bin\tests\Windows_NT.$(archType).$(buildConfigUpper)\tests\core_root /p:__BuildType=$(buildConfig) /p:__BuildArch=$(archType) /p:UsePython=true + displayName: Prepare test archives for Helix + + + # Send tests to helix + - ${{ if or(eq(parameters.osGroup, 'Linux'), eq(parameters.osGroup, 'OSX')) }}: + - script: ./Tools/dotnetcli/dotnet msbuild tests/helixpublishwitharcade.proj /t:Test $(scenariosArg) + displayName: Send test jobs to Helix + env: + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + # Access token variable for internal project + HelixAccessToken: $(HelixApiAccessToken) + ${{ if eq(variables['System.TeamProject'], 'public') }}: + # Access token variable for public project + HelixAccessToken: $(BotAccount-dotnet-github-anon-kaonashi-bot-helix-token) + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + - script: .\Tools\dotnetcli\dotnet msbuild tests\helixpublishwitharcade.proj /t:Test $(scenariosArg) + displayName: Send test jobs to Helix + env: + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + # Access token variable for internal project + HelixAccessToken: $(HelixApiAccessToken) + ${{ if eq(variables['System.TeamProject'], 'public') }}: + # Access token variable for public project + HelixAccessToken: $(BotAccount-dotnet-github-anon-kaonashi-bot-helix-token) diff --git a/eng/xplat-job.yml b/eng/xplat-job.yml new file mode 100644 index 0000000000..ba15cc0555 --- /dev/null +++ b/eng/xplat-job.yml @@ -0,0 +1,50 @@ +parameters: + buildConfig: '' + archType: '' + osGroup: '' + name: '' + displayName: '' + condition: '' + dependsOn: '' + variables: {} ## any extra variables to add to the defaults defined below + +jobs: +- template: /eng/common/templates/phases/base.yml@arcade + parameters: + + name: ${{ parameters.name }} + displayName: ${{ parameters.displayName }} + + condition: ${{ parameters.condition }} + + dependsOn: ${{ parameters.dependsOn }} + + queue: + ${{ if eq(parameters.osGroup, 'Linux') }}: + name: Hosted Ubuntu 1604 + ${{ if eq(parameters.osGroup, 'OSX') }}: + name: Hosted macOS + ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + name: dotnet-external-temp + timeoutInMinutes: 180 + + ${{ if eq(parameters.osGroup, 'Linux') }}: + agentOs: Ubuntu + ${{ if eq(parameters.osGroup, 'OSX') }}: + agentOs: MacOS + ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + agentOs: Windows_NT + + variables: + buildConfig: ${{ parameters.buildConfig }} + ${{ if eq(parameters.buildConfig, 'checked') }}: + buildConfigUpper: 'Checked' + ${{ if eq(parameters.buildConfig, 'debug') }}: + buildConfigUpper: 'Debug' + ${{ if eq(parameters.buildConfig, 'release') }}: + buildConfigUpper: 'Release' + archType: ${{ parameters.archType }} + osGroup: ${{ parameters.osGroup }} + ${{insert}}: ${{ parameters.variables }} + + steps: ${{ parameters.steps }} diff --git a/src/pal/tools/probe-win.ps1 b/src/pal/tools/probe-win.ps1 index fa30d9cb40..5fc499a8c6 100644 --- a/src/pal/tools/probe-win.ps1 +++ b/src/pal/tools/probe-win.ps1 @@ -46,7 +46,7 @@ function LocateCMake $validVersions = @() foreach ($regKey in GetCMakeVersions) { $info = GetCMakeInfo($regKey) - if ($info -ne $null) { + if ($info -ne $null) { $validVersions += @($info) } } diff --git a/src/publishwitharcade.proj b/src/publishwitharcade.proj new file mode 100644 index 0000000000..01bc997288 --- /dev/null +++ b/src/publishwitharcade.proj @@ -0,0 +1,37 @@ +<Project DefaultTargets="PublishProductPackages" Sdk="Microsoft.DotNet.Arcade.Sdk"> + + <!-- TODO: move properties imported from here into a common props file --> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + + <Import Project="$(NuGetPackageRoot)microsoft.dotnet.build.tasks.feed\$(MicrosoftDotNetBuildTasksFeedVersion)\build\Microsoft.DotNet.Build.Tasks.Feed.targets" /> + + <Target Name="PublishPackages"> + + <ItemGroup> + <ItemsToPush Remove="*.nupkg" /> + <ItemsToPush Include="$(PackagesBinDir)pkg\*.nupkg"> + <ManifestArtifactData>NonShipping=true</ManifestArtifactData> <!-- TODO: how is this metadata used? --> + </ItemsToPush> + </ItemGroup> + + <Error Condition=" '$(AzureFeedUrl)' == '' " Text="AzureFeedUrl must be set" /> + <Error Condition=" '$(AccountKey)' == '' " Text="AccountKey must be set" /> + <Error Condition=" '$(BUILD_REPOSITORY_URI)' == '' " Text="BUILD_REPOSITORY_URI must be set" /> + <Error Condition=" '$(BUILD_SOURCEBRANCH)' == '' " Text="BUILD_SOURCEBRANCH must be set" /> + <Error Condition=" '$(BUILD_BUILDNUMBER)' == '' " Text="BUILD_BUILDNUMBER must be set" /> + <Error Condition=" '$(BUILD_SOURCEVERSION)' == '' " Text="BUILD_SOURCEVERSION must be set" /> + + <PushToBlobFeed ExpectedFeedUrl="$(AzureFeedUrl)" + AccountKey="$(AccountKey)" + ItemsToPush="@(ItemsToPush)" + ManifestBuildData="Location=$(AzureFeedUrl)" + ManifestRepoUri="$(BUILD_REPOSITORY_URI)" + ManifestBranch="$(BUILD_SOURCEBRANCH)" + ManifestBuildId="$(BUILD_BUILDNUMBER)" + ManifestCommit="$(BUILD_SOURCEVERSION)" /> + <!-- TODO: The arcade sample publishes an asset manifest. Do we want this? + AssetManifestPath="" /> + --> + </Target> + +</Project> diff --git a/src/restorearcadepublishtasks.proj b/src/restorearcadepublishtasks.proj new file mode 100644 index 0000000000..21d8c61a7e --- /dev/null +++ b/src/restorearcadepublishtasks.proj @@ -0,0 +1,16 @@ +<Project Sdk="Microsoft.DotNet.Arcade.Sdk"> + + <PropertyGroup> + <TargetFramework>net462</TargetFramework> + <RestoreSources/> + <RestoreSources> + $(RestoreSources); + https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json + </RestoreSources> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.DotNet.Build.Tasks.Feed" Version="$(MicrosoftDotNetBuildTasksFeedVersion)" /> + </ItemGroup> + +</Project> diff --git a/tests/helixprep.proj b/tests/helixprep.proj index 1cbf0ed0f8..50d7d9bd76 100644 --- a/tests/helixprep.proj +++ b/tests/helixprep.proj @@ -1,23 +1,26 @@ <Project ToolsVersion="12.0" DefaultTargets="ArchiveAll" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <UsingTask TaskName="ZipFileCreateFromDirectory" AssemblyFile="$(ToolsDir)\net46\Microsoft.DotNet.Build.Tasks.dll"/> - + <UsingTask TaskName="ZipFileCreateFromDirectory" AssemblyFile="$(ToolsDir)\net46\Microsoft.DotNet.Build.Tasks.dll" + Condition=" '$(MSBuildRuntimeType)' != 'Core' " /> + <UsingTask TaskName="ZipFileCreateFromDirectory" AssemblyFile="$(ToolsDir)\Microsoft.DotNet.Build.Tasks.dll" + Condition=" '$(MSBuildRuntimeType)' == 'Core' " /> + <Import Project="dir.props" /> <Import Project="..\dir.props" /> <PropertyGroup> <DiscoveryDirectory>$(TestWorkingDir)</DiscoveryDirectory> - <CoreRootDir>$(CORE_ROOT)</CoreRootDir> <CoreRootName>Core_Root_$(RuntimeID)</CoreRootName> + <UsePython Condition=" '$(UsePython)' == '' ">false</UsePython> </PropertyGroup> <ItemGroup> - <TestCmds Include="$(DiscoveryDirectory)\**\*.cmd" ></TestCmds> <XunitDlls Include="$(DiscoveryDirectory)\**\*.XUnitWrapper.dll" ></XunitDlls> <RequiresSigningFilesToDelete Include="$(DiscoveryDirectory)\**\*.requires_signing" /> </ItemGroup> <!-- Build the platform-specific wrapper to run an individual xunit wrapper --> + <!-- We should remove the generated wrappers once we have transitioned our official build --> <Target Name="GenerateWrapperExecutables" Inputs="@(XunitDlls)" @@ -32,15 +35,26 @@ Targets="GenerateWrapperSh" /> </Target> + <!-- Copy the wrapper script to the xunit directory --> + <Target Name="CopyWrapperScript" + Inputs="@(XunitDlls)" + Outputs="$(TestWorkingDir)*\runtest_helix.py" > + + <Copy SourceFiles="$(MSBuildThisFileDirectory)\runtest_helix.py" + DestinationFolder="%(XunitDlls.RootDir)%(XunitDlls.Directory)" /> + + </Target> + <!-- Zip each top-level test folder to send to Helix --> <Target Name="ArchiveTests" Inputs="@(XunitDlls)" Outputs="$(TestWorkingDir)archive\**" > - + <Copy SourceFiles="$(CORE_ROOT)\xunit.console.dll" DestinationFolder="%(XunitDlls.RootDir)%(XunitDlls.Directory)" - /> + Condition=" '$(UsePython)' == 'false' " /> + <Message Text="Deleting '.requires_signing' files to avoid file name lengths exceeding MAX_PATH" Importance="Low" /> <Delete Files="@(RequiresSigningFilesToDelete)" /> <MSBuild Projects="helixprep.proj" @@ -52,10 +66,10 @@ <!-- Zip Core_Root & Packages payload to send to Helix --> <Target Name="ArchiveCoreRoot" - Inputs="$(CoreRootDir)" + Inputs="$(CORE_ROOT)" Outputs="$(TestWorkingDir)archive\Core_Root" > <MSBuild Projects="helixprep.proj" - Properties="BuildPath=$(CoreRootDir);ProjectName=$(CoreRootName);BuildArchiveDir=$(TestWorkingDir)archive\Core_Root\" + Properties="BuildPath=$(CORE_ROOT);ProjectName=$(CoreRootName);BuildArchiveDir=$(TestWorkingDir)archive\Core_Root\" Targets="ArchiveBuild" /> <!-- Make dummy packages.zip to upload to Helix --> @@ -180,8 +194,13 @@ EXIT /B %ERRORLEVEL% <!-- Default target to run - builds executables & archives everything needed for Helix run --> <Target Name="ArchiveAll" > + <PropertyGroup> + <_ArchiveTargets Condition=" '$(UsePython)' == 'false' ">GenerateWrapperExecutables</_ArchiveTargets> + <_ArchiveTargets Condition=" '$(UsePython)' == 'true' ">CopyWrapperScript</_ArchiveTargets> + <_ArchiveTargets>$(_ArchiveTargets);ArchiveTests;ArchiveCoreRoot</_ArchiveTargets> + </PropertyGroup> <MSBuild Projects="helixprep.proj" - Targets="GenerateWrapperExecutables;ArchiveTests;ArchiveCoreRoot" /> + Targets="$(_ArchiveTargets)" /> </Target> -</Project>
\ No newline at end of file +</Project> diff --git a/tests/helixpublishwitharcade.proj b/tests/helixpublishwitharcade.proj new file mode 100644 index 0000000000..38fb8d2589 --- /dev/null +++ b/tests/helixpublishwitharcade.proj @@ -0,0 +1,93 @@ +<Project Sdk="Microsoft.DotNet.Helix.Sdk"> + + <!-- This project uses the helix SDK ,documented at + https://github.com/dotnet/arcade/tree/master/src/Microsoft.DotNet.Helix/Sdk, + to send test jobs to helix. --> + + <Import Project="..\dir.props" /> + + <PropertyGroup> + <!-- TODO: pick appropriate helix source and type. --> + <HelixSource>pr/coreclr/master</HelixSource> + <HelixType>test/stuff</HelixType> + <HelixBuild>$(BUILD_BUILDNUMBER)</HelixBuild> + + <!-- TODO: add target queues for rhel and linux-musl --> + <!-- TODO: why don't we currently run tests on windows x86? --> + <HelixTargetQueues Condition=" '$(BuildOS)' == 'Windows_NT' "> + Windows.10.Amd64; + Windows.10.Nano.Amd64; + Windows.10.Amd64.Core; + Windows.7.Amd64; + Windows.81.Amd64 + </HelixTargetQueues> + <HelixTargetQueues Condition=" '$(BuildOS)' == 'Linux' "> + debian.82.amd64; + fedora.27.amd64; + fedora.28.amd64; + redhat.73.amd64; + ubuntu.1404.amd64; + ubuntu.1604.amd64; + ubuntu.1804.amd64; + opensuse.423.amd64; + sles.12.amd64 + </HelixTargetQueues> + <HelixTargetQueues Condition=" '$(BuildOS)' == 'OSX' "> + osx.1012.amd64; + osx.1013.amd64 + </HelixTargetQueues> + + <EnableXUnitReporter>true</EnableXUnitReporter> + <WaitForWorkItemCompletion>true</WaitForWorkItemCompletion> + <SourceDirectory>$(MSBuildProjectDirectory)/..</SourceDirectory> + </PropertyGroup> + + <ItemGroup> + <HelixCorrelationPayload Include="$(SourceDirectory)\bin\tests\*\archive\Core_Root\*.zip"> + <PayloadArchive>%(Identity)</PayloadArchive> + </HelixCorrelationPayload> + </ItemGroup> + + <Target Name="SubmitTestsToHelix"> + <ItemGroup> + <Scenarios Include="$(Scenarios)" /> + </ItemGroup> + + <!-- If no scenario was specified, just run the normal test + scenario --> + <MSBuild Projects="$(MSBuildProjectFile)" Targets="Test" + Condition=" '@(Scenarios->Count())' == '0' " /> + + <!-- If scenarios were specified, submit jobs for each + scenario. --> + <MSBuild Projects="$(MSBuildProjectFile)" Targets="Test" + Properties="Scenario=%(Scenarios.Identity)" + BuildInParallel="true" + Condition=" '@(Scenarios->Count())' != '0' " /> + + </Target> + + <Target Name="BuildHelixWorkItem" + BeforeTargets="Test"> + <PropertyGroup> + <!-- The "normal" scenario is just a way to include the default + (empty) scenario when specifying multiple scenarios at + once. From here, on, treat it as the empty scenario so that + job names will not have a scenario prefix and the runtest + script doesn't have to define a "normal" scenario. --> + <Scenario Condition=" '$(Scenario)' == 'normal' "></Scenario> + <ScenarioPrefix Condition=" '$(Scenario)' == '' " /> + <ScenarioPrefix Condition=" '$(Scenario)' != '' ">$(Scenario) </ScenarioPrefix> + </PropertyGroup> + <ItemGroup> + <TestZipFiles Include="$(SourceDirectory)\bin\tests\*\archive\tests\*.zip" /> + <HelixWorkItem Include="@(TestZipFiles->'$(ScenarioPrefix)%(FileName)')" > + <PayloadArchive>%(Identity)</PayloadArchive> + <Command Condition=" '$(Scenario)' == '' ">python runtest_helix.py -wrapper %(FileName).dll</Command> + <Command Condition=" '$(Scenario)' != '' ">python runtest_helix.py -scenario $(Scenario) -wrapper %(FileName).dll</Command> + </HelixWorkItem> + </ItemGroup> + + </Target> + +</Project> diff --git a/tests/runtest_helix.py b/tests/runtest_helix.py new file mode 100755 index 0000000000..910d9d77ce --- /dev/null +++ b/tests/runtest_helix.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python + +# This script runs tests in helix. It defines a set of test scenarios +# that enable various combinations of runtime configurations to be set +# via the test process environment. + +# This script calls "corerun xunit.console.dll xunitwrapper.dll", +# where the xunitwrapper.dll will run a .sh/.cmd script per test in a +# separate process. This process will have the scenario environment +# variables set, but the xunit process will not. + +# TODO: Factor out logic common with runtest.py + +import argparse +import subprocess +import os +import sys +import tempfile + +test_scenarios = { + "jitstress2": { "COMPlus_TieredCompilation": "0", + "COMPlus_JitStress": "2" }, +} + +if sys.platform == "linux" or sys.platform == "darwin": + platform_type = "unix" +elif sys.platform == "win32": + platform_type = "windows" +else: + print("unknown os: %s" % sys.platform) + sys.exit(1) + +def get_testenv_script(env_dict): + if platform_type == "unix": + return ''.join([ "export %s=%s%s" % (k, v, os.linesep) for k, v in env_dict.items() ]) + elif platform_type == "windows": + return ''.join([ "set %s=%s%s" % (k, v, os.linesep) for k, v in env_dict.items() ]) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Parse arguments") + parser.add_argument("-scenario", dest="scenario", default=None) + parser.add_argument("-wrapper", dest="wrapper", default=None, required=True) + args = parser.parse_args() + scenario = args.scenario + wrapper = args.wrapper + + if not "HELIX_CORRELATION_PAYLOAD" in os.environ: + print("HELIX_CORRELATION_PAYLOAD must be defined in environment") + sys.exit(1) + + if not "HELIX_WORKITEM_PAYLOAD" in os.environ: + print("HELIX_WORKITEM_PAYLOAD must be defined in environment") + sys.exit(1) + + core_root = os.environ["HELIX_CORRELATION_PAYLOAD"] + + if platform_type == "unix": + corerun = os.path.join(core_root, "corerun") + else: + corerun = os.path.join(core_root, "corerun.exe") + + # Unlike the old test wrapper, this runs xunit.console.dll from + # the correlation payload. This removes the need for redundant + # copies of the console runner in each test directory. + command = [corerun, + os.path.join(os.environ["HELIX_CORRELATION_PAYLOAD"], "xunit.console.dll"), + os.path.join(os.environ["HELIX_WORKITEM_PAYLOAD"], wrapper), + "-noshadow", + "-xml", "testResults.xml", + "-notrait", "category=outerloop", + "-notrait", "category=failing"] + + if scenario is None: + print("CORE_ROOT=%s" % core_root) + os.environ["CORE_ROOT"] = core_root + + print("BEGIN EXECUTION") + print(' '.join(command)) + proc = subprocess.Popen(command) + proc.communicate() + print("Finished running tests. Exit code = %d" % proc.returncode) + sys.exit(proc.returncode) + else: + print("scenario: %s" % scenario) + with tempfile.NamedTemporaryFile(mode="w") as testenv: + testenv.write(get_testenv_script(test_scenarios[scenario])) + testenv.flush() + + print("__TestEnv=%s" % testenv.name) + os.environ["__TestEnv"] = testenv.name + + with open(testenv.name) as testenv_written: + contents = testenv_written.read() + print(contents) + + print("CORE_ROOT=%s" % core_root) + os.environ["CORE_ROOT"] = core_root + + print("BEGIN EXECUTION") + print(' '.join(command)) + proc = subprocess.Popen(command) + proc.communicate() + print("Finished running tests. Exit code = %d" % proc.returncode) + sys.exit(proc.returncode) |