diff --git a/pipelines/ci-daily.yml b/pipelines/ci-daily.yml index 46fe3e5f823..f85aafd8efd 100644 --- a/pipelines/ci-daily.yml +++ b/pipelines/ci-daily.yml @@ -16,10 +16,10 @@ jobs: - SDK_18362 -equals TRUE - VS2019 -equals TRUE steps: - - template: templates/common-Unity2019.yml + - template: templates/common.yml parameters: - packagingEnabled: false UnityVersion: $(Unity2019Version) + buildUWPArm64: true - job: Unity2018Validation timeoutInMinutes: 120 diff --git a/pipelines/pr-2020.yaml b/pipelines/pr-2020.yaml index 6c5f317fe36..47cf40ffea3 100644 --- a/pipelines/pr-2020.yaml +++ b/pipelines/pr-2020.yaml @@ -24,9 +24,7 @@ jobs: # the specific flavors below that are experiencing failures in CI (for example, # if we're actively working on features that have a lot of churn on underlying # WMR APIs, buildUWPArm would be a good candidate to re-enable) - buildUWPX86: false - buildUWPArm: false - buildUWPDotNet: false + buildStandalone: true UnityVersion: $(Unity2020Version) - template: templates/end.yml diff --git a/pipelines/pr.yaml b/pipelines/pr.yaml index 7b1668c518b..aee8d084244 100644 --- a/pipelines/pr.yaml +++ b/pipelines/pr.yaml @@ -23,9 +23,7 @@ jobs: # the specific flavors below that are experiencing failures in CI (for example, # if we're actively working on features that have a lot of churn on underlying # WMR APIs, buildUWPArm would be a good candidate to re-enable) - buildUWPX86: false - buildUWPArm: false - buildUWPDotNet: false + buildStandalone: true UnityVersion: $(Unity2018Version) - job: Unity2019Validation @@ -40,8 +38,6 @@ jobs: steps: - template: templates/common.yml parameters: - buildUWPX86: false - buildUWPArm: false - buildUWPDotNet: false + buildStandalone: true UnityVersion: $(Unity2019Version) - template: templates/end.yml diff --git a/pipelines/templates/ci-common.yml b/pipelines/templates/ci-common.yml index 94750061d3b..338b0fd7228 100644 --- a/pipelines/templates/ci-common.yml +++ b/pipelines/templates/ci-common.yml @@ -9,8 +9,10 @@ parameters: steps: - template: common.yml parameters: - buildUWPDotNet: false UnityVersion: ${{ parameters.UnityVersion }} + buildStandalone: true + buildUWPx86: true + buildUWPArm: true - template: tasks/versionmetadata.yml - ${{ if eq(parameters.packagingEnabled, true) }}: - ${{ if eq(parameters.packageNuGet, true) }}: diff --git a/pipelines/templates/common-Unity2019.yml b/pipelines/templates/common-Unity2019.yml deleted file mode 100644 index 6364a5225bb..00000000000 --- a/pipelines/templates/common-Unity2019.yml +++ /dev/null @@ -1,20 +0,0 @@ -# [Template] Common build tasks shared between CI builds and PR validation. - -parameters: - UnityVersion: "" - -steps: -# Build UWP ARM64. -- template: tasks/unitybuild.yml - parameters: - Arch: 'arm64' - Platform: 'UWP' - PackagingDir: 'ARM64' - UnityVersion: ${{ parameters.UnityVersion }} - PublishArtifacts: true - -- template: tests.yml - parameters: - UnityVersion: ${{ parameters.UnityVersion }} - -- template: end.yml diff --git a/pipelines/templates/common.yml b/pipelines/templates/common.yml index cfdf221a801..8d347695b22 100644 --- a/pipelines/templates/common.yml +++ b/pipelines/templates/common.yml @@ -2,23 +2,31 @@ parameters: UnityVersion: "" - buildStandalone: true - buildUWPArm: true - buildUWPDotNet: true - buildUWPX86: true + buildStandalone: false + buildUWPx86: false + buildUWPArm: false + buildUWPArm64: false runTests: true steps: +- powershell: | + # Module management requires TLS 1.2. + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + if (-not (Get-InstalledModule -Name UnitySetup)) { + Install-Module -Name UnitySetup -Scope CurrentUser -Force + } + displayName: Install unitysetup.powershell + # Build Standalone x64. # This must happen before tests run, because if the build fails and tests attempt # to get run, Unity will hang showing a dialog (even when in batch mode). # This is the fastest build, since it doesn't produce an AppX. - ${{ if eq(parameters.buildStandalone, true) }}: - - template: tasks/unitybuild.yml + - template: unity.yaml parameters: - Arch: 'x64' - Platform: 'Standalone' UnityVersion: ${{ parameters.UnityVersion }} + BuildTarget: StandaloneWindows64 + OutputPath: $(Build.ArtifactStagingDirectory)/mrtk-build-exe-x64/MixedRealityToolkit.exe # Tests should run earlier in the process, so that engineers can get test failure # notifications earlier in the CI process. @@ -27,31 +35,55 @@ steps: parameters: UnityVersion: ${{ parameters.UnityVersion }} -# Build UWP x86 -- ${{ if eq(parameters.buildUWPX86, true) }}: - - template: tasks/unitybuild.yml +# Build UWP. +- ${{ if or(eq(parameters.buildUWPx86, true), eq(parameters.buildUWPArm, true), eq(parameters.buildUWPArm64, true)) }}: + - template: unity.yaml parameters: - Arch: 'x86' - Platform: 'UWP' - PublishArtifacts: true UnityVersion: ${{ parameters.UnityVersion }} + BuildTarget: WSAPlayer + OutputPath: $(Agent.TempDirectory)/build/uwp -# Build UWP ARM -- ${{ if eq(parameters.buildUWPArm, true) }}: - - template: tasks/unitybuild.yml - parameters: - Arch: 'arm' - Platform: 'UWP' - PublishArtifacts: true - PackagingDir: 'ARM' - UnityVersion: ${{ parameters.UnityVersion }} + # Build UWP x86. + - ${{ if eq(parameters.buildUWPx86, true) }}: + - template: tasks/build-appx.yaml + parameters: + ProjectName: MixedRealityToolkit + Architectures: [x86] + BuildFolderPath: $(Agent.TempDirectory)/build/uwp + Version: $(MRTKVersion) -# Build UWP x86 .NET backend -- ${{ if eq(parameters.buildUWPDotNet, true) }}: - - template: tasks/unitybuild.yml - parameters: - Arch: 'x86' - Platform: 'UWP' - PublishArtifacts: true - ScriptingBackend: '.NET' - UnityVersion: ${{ parameters.UnityVersion }} + - task: PublishBuildArtifacts@1 + displayName: Publish x86 AppX + inputs: + ArtifactName: mrtk-build-x86 + PathToPublish: $(Build.ArtifactStagingDirectory)/Apps/uwp-x86 + + # Build UWP ARM. + - ${{ if eq(parameters.buildUWPArm, true) }}: + - template: tasks/build-appx.yaml + parameters: + ProjectName: MixedRealityToolkit + Architectures: [ARM] + BuildFolderPath: $(Agent.TempDirectory)/build/uwp + Version: $(MRTKVersion) + + - task: PublishBuildArtifacts@1 + displayName: Publish ARM AppX + inputs: + ArtifactName: mrtk-build-arm + PathToPublish: $(Build.ArtifactStagingDirectory)/Apps/uwp-arm + + # Build UWP ARM64. + - ${{ if eq(parameters.buildUWPArm64, true) }}: + - template: tasks/build-appx.yaml + parameters: + ProjectName: MixedRealityToolkit + Architectures: [ARM64] + BuildFolderPath: $(Agent.TempDirectory)/build/uwp + Version: $(MRTKVersion) + + - task: PublishBuildArtifacts@1 + displayName: Publish ARM64 AppX + inputs: + ArtifactName: mrtk-build-arm64 + PathToPublish: $(Build.ArtifactStagingDirectory)/Apps/uwp-arm64 diff --git a/pipelines/templates/tasks/assetretargeting.yml b/pipelines/templates/tasks/assetretargeting.yml index 4a4f840390e..2ed51ae09f7 100644 --- a/pipelines/templates/tasks/assetretargeting.yml +++ b/pipelines/templates/tasks/assetretargeting.yml @@ -5,9 +5,11 @@ parameters: steps: - powershell: | - # Some machines require that the protocol be explicitly set to Tls12 + # Module management requires TLS 1.2. [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - Install-Module -Name UnitySetup -Scope CurrentUser -Force + if (-not (Get-InstalledModule -Name UnitySetup)) { + Install-Module -Name UnitySetup -Scope CurrentUser -Force + } displayName: Install unitysetup.powershell - powershell: | diff --git a/pipelines/templates/tasks/build-appx.yaml b/pipelines/templates/tasks/build-appx.yaml new file mode 100644 index 00000000000..b318e6fe936 --- /dev/null +++ b/pipelines/templates/tasks/build-appx.yaml @@ -0,0 +1,36 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# [Template] Build appx from a Unity-built sln. + +parameters: +- name: ProjectName + type: string + +- name: Architectures + type: object + default: [] + +- name: BuildFolderPath + type: string + +- name: Version + type: string + +steps: +- ${{ each arch in parameters.Architectures }}: + - task: MSBuild@1 + displayName: Build ${{ arch }} AppX + inputs: + solution: ${{ parameters.BuildFolderPath }}/${{ parameters.ProjectName }}.sln + platform: ${{ arch }} + configuration: Master + + - task: CopyFiles@2 + displayName: Copy ${{ arch }} AppX to artifacts staging directory + inputs: + ${{ if eq(arch, 'x86') }}: + sourceFolder: ${{ parameters.BuildFolderPath }}/AppPackages/${{ parameters.ProjectName }}/${{ parameters.ProjectName }}_${{ parameters.Version }}.0_Win32_Master_Test + ${{ if not(eq(arch, 'x86')) }}: + sourceFolder: ${{ parameters.BuildFolderPath }}/AppPackages/${{ parameters.ProjectName }}/${{ parameters.ProjectName }}_${{ parameters.Version }}.0_${{ arch }}_Master_Test + targetFolder: $(Build.ArtifactStagingDirectory)/Apps/uwp-${{ arch }} diff --git a/pipelines/templates/tasks/build-unity.yaml b/pipelines/templates/tasks/build-unity.yaml new file mode 100644 index 00000000000..7fe018a00e4 --- /dev/null +++ b/pipelines/templates/tasks/build-unity.yaml @@ -0,0 +1,68 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# [Template] Build project inside Unity. + +parameters: +- name: UnityVersion + type: string + +- name: BuildTarget + type: string + values: + - StandaloneWindows64 + - WSAPlayer + - Android + +- name: CommandLineBuildMethod + type: string + +- name: PathToProject + type: string + +- name: OutputPath + type: string + +- name: AdditionalArguments + type: string + default: '' + +steps: +- powershell: | + $logFile = Join-Path $(Agent.TempDirectory) "build_${{ parameters.BuildTarget }}.log" + New-Item -Path $logFile -ItemType File -Force + $proc = Start-UnityEditor -Project ${{ parameters.PathToProject }} -Version ${{ parameters.UnityVersion }} -ExecuteMethod ${{ parameters.CommandLineBuildMethod }} -BatchMode -Quit -PassThru -LogFile $logFile -BuildTarget ${{ parameters.BuildTarget }} -OutputPath ${{ parameters.OutputPath }} -AdditionalArguments "${{ parameters.AdditionalArguments }}" + $ljob = Start-Job -ScriptBlock { param($log) Get-Content "$log" -Wait } -ArgumentList $logFile + + while (-not $proc.HasExited -and $ljob.HasMoreData) { + Receive-Job $ljob + Start-Sleep -Milliseconds 200 + } + + Stop-Job $ljob + Remove-Job $ljob + Stop-Process $proc + + Write-Output '=====================================================' + Write-Output ' Unity Build Player Finished ' + Write-Output '=====================================================' + + if (Test-Path $logFile) { + Write-Output '=====================================================' + Write-Output ' Begin Unity Player Log ' + Write-Output '=====================================================' + + Get-Content $logFile + + Write-Output '=====================================================' + Write-Output ' End Unity Player Log ' + Write-Output '=====================================================' + } + else { + Write-Output 'Unity Player log missing!' + } + + if ($proc.ExitCode -ne 0) { + exit $proc.ExitCode + } + displayName: Build ${{ parameters.BuildTarget }} diff --git a/pipelines/templates/tasks/generate-projects.yml b/pipelines/templates/tasks/generate-projects.yml index 7a9c83e426c..2f23842950f 100644 --- a/pipelines/templates/tasks/generate-projects.yml +++ b/pipelines/templates/tasks/generate-projects.yml @@ -5,9 +5,11 @@ parameters: steps: - powershell: | - # Some machines require that the protocol be explicitly set to Tls12 + # Module management requires TLS 1.2. [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - Install-Module -Name UnitySetup -Scope CurrentUser -Force + if (-not (Get-InstalledModule -Name UnitySetup)) { + Install-Module -Name UnitySetup -Scope CurrentUser -Force + } displayName: Install unitysetup.powershell - powershell: | diff --git a/pipelines/templates/tasks/unitybuild.yml b/pipelines/templates/tasks/unitybuild.yml deleted file mode 100644 index 827e7d6cc54..00000000000 --- a/pipelines/templates/tasks/unitybuild.yml +++ /dev/null @@ -1,175 +0,0 @@ -# [Template] Compile MRTK inside Unity. - -parameters: -- name: Arch - type: string - values: - - x86 - - x64 - - arm - - arm64 -- name: Platform - type: string - values: - - UWP - - Standalone -- name: UnityArgs # [optional] additional args passed to Unity - type: string - default: none -- name: ScriptingBackend # [optional] - type: string - default: default - values: - - default - - .NET -- name: PublishArtifacts - type: boolean - default: false -- name: PackagingDir - type: string - default: Win32 -- name: UnityVersion - type: string - -steps: -- powershell: | - $UnityPath = ${Env:${{ parameters.UnityVersion }}} - # Find unity.exe as Start-UnityEditor currently doesn't support arbitrary parameters - $editor = Get-ChildItem $UnityPath -Filter 'Unity.exe' -Recurse | Select-Object -First 1 -ExpandProperty FullName - - # The build output goes to a unique combination of Platform + Arch + ScriptingBackend to ensure that - # each build will have a fresh destination folder. - $outDir = "$(Build.ArtifactStagingDirectory)\build\${{ parameters.Platform }}_${{ parameters.Arch }}_${{ parameters.ScriptingBackend }}" - $logFile = New-Item -Path "$outDir\build\build.log" -ItemType File -Force - $logDirectory = "$outDir\logs" - - $sceneList = "Assets\MRTK\Examples\Demos\HandTracking\Scenes\HandInteractionExamples.unity" - - $extraArgs = "" - if ("${{ parameters.Platform }}" -eq "UWP") - { - $extraArgs += '-buildTarget WSAPlayer -buildAppx' - } - elseif ("${{ parameters.Platform }}" -eq "Standalone") - { - $extraArgs += "-buildTarget StandaloneWindows" - - if ("${{ parameters.Arch }}" -eq "x64") - { - $extraArgs += "64" - } - } - - if ("${{ parameters.UnityArgs }}" -ne "none") - { - $extraArgs += " ${{ parameters.UnityArgs }}" - } - - if ("${{ parameters.ScriptingBackend }}" -eq ".NET") - { - $extraArgs += " -scriptingBackend 2" - } - - $proc = Start-Process -FilePath "$editor" -ArgumentList "-projectPath $(Get-Location) -executeMethod Microsoft.MixedReality.Toolkit.Build.Editor.UnityPlayerBuildTools.StartCommandLineBuild -sceneList $sceneList -logFile $($logFile.FullName) -batchMode -${{ parameters.Arch }} -buildOutput $outDir $extraArgs -CacheServerIPAddress ${Env:COG-UnityCache-WUS2-01} -logDirectory $logDirectory" -PassThru - $ljob = Start-Job -ScriptBlock { param($log) Get-Content "$log" -Wait } -ArgumentList $logFile.FullName - - while (-not $proc.HasExited -and $ljob.HasMoreData) - { - Receive-Job $ljob - Start-Sleep -Milliseconds 200 - } - Receive-Job $ljob - - Stop-Job $ljob - - Remove-Job $ljob - Stop-Process $proc - - Write-Output '=====================================================' - Write-Output ' Unity Build Player Finished ' - Write-Output '=====================================================' - - if (Test-Path $logFile.FullName) - { - Write-Output '=====================================================' - Write-Output ' Begin Unity Player Log ' - Write-Output '=====================================================' - - Get-Content $logFile.FullName - - Write-Output '=====================================================' - Write-Output ' End Unity Player Log ' - Write-Output '=====================================================' - } - else - { - Write-Output 'Unity Player Log Missing!' - } - - # The NuGet and AppX logs are only relevant for UWP builds. - if ("${{ parameters.Platform }}" -eq "UWP") - { - $nugetRestoreLogFileName = "$logDirectory\nugetRestore.log" - if (Test-Path $nugetRestoreLogFileName) - { - Write-Output '=====================================================' - Write-Output ' Begin NuGet Restore Log ' - Write-Output '=====================================================' - - Get-Content $nugetRestoreLogFileName - - Write-Output '=====================================================' - Write-Output ' End NuGet Restore Log ' - Write-Output '=====================================================' - } - else - { - Write-Output "NuGet Restore Log Missing $nugetRestoreLogFileName!" - } - - $appxBuildLogFileName = "$logDirectory\buildAppx.log" - if (Test-Path $appxBuildLogFileName) - { - Write-Output '=====================================================' - Write-Output ' Begin AppX Build Log ' - Write-Output '=====================================================' - - Get-Content $appxBuildLogFileName - - Write-Output '=====================================================' - Write-Output ' End AppX Build Log ' - Write-Output '=====================================================' - } - else - { - Write-Output "AppX Build Log Missing $appxBuildLogFileName!" - } - } - - if ($proc.ExitCode -ne 0) - { - exit $proc.ExitCode - } - displayName: "Build ${{ parameters.Platform }} ${{ parameters.Arch }} ${{ parameters.ScriptingBackend }}" - -- task: PowerShell@2 - displayName: Validate build logs - inputs: - targetType: filePath - filePath: ./scripts/ci/validatebuildlog.ps1 - arguments: > - -LogFile: '$(Build.ArtifactStagingDirectory)\build\${{ parameters.Platform }}_${{ parameters.Arch }}_${{ parameters.ScriptingBackend }}\build\build.log' - -- task: PublishBuildArtifacts@1 - enabled: ${{ parameters.PublishArtifacts }} - displayName: Publish ${{ parameters.Platform }} ${{ parameters.Arch }} (${{ parameters.PackagingDir }}) ${{ parameters.ScriptingBackend }} - inputs: - ArtifactName: 'mrtk-build-${{ parameters.Arch }}' - # The final location of the generated package depends on the type of scripting backend it's built against. - # For the default scripting backend (IL2CPP) the naming of the appx follows the form below: - ${{ if eq(parameters.ScriptingBackend, 'default') }}: - PathtoPublish: '$(Build.ArtifactStagingDirectory)\build\${{ parameters.Platform }}_${{ parameters.Arch }}_${{ parameters.ScriptingBackend }}\AppPackages\MixedRealityToolkit\MixedRealityToolkit_$(MRTKVersion).0_${{ parameters.PackagingDir }}_Master_Test' - # For .NET scripting backends, the naming is slightly different (mainly the AppPackages and MixedRealityToolkit folder - # names are reversed, and the Architecture is part of the AppX name) - ${{ if eq(parameters.ScriptingBackend, '.NET') }}: - PathtoPublish: '$(Build.ArtifactStagingDirectory)\build\${{ parameters.Platform }}_${{ parameters.Arch }}_${{ parameters.ScriptingBackend }}\MixedRealityToolkit\AppPackages\MixedRealityToolkit_$(MRTKVersion).0_${{ parameters.Arch }}_Master_Test' diff --git a/pipelines/templates/unity.yaml b/pipelines/templates/unity.yaml new file mode 100644 index 00000000000..04724ea9192 --- /dev/null +++ b/pipelines/templates/unity.yaml @@ -0,0 +1,33 @@ +# [Template] Build project inside Unity. + +parameters: +- name: UnityVersion + type: string + +- name: BuildTarget + type: string + values: + - StandaloneWindows64 + - WSAPlayer + - Android + +- name: OutputPath + type: string + +steps: +- template: tasks/build-unity.yaml + parameters: + UnityVersion: ${{ parameters.UnityVersion }} + BuildTarget: ${{ parameters.BuildTarget }} + CommandLineBuildMethod: Microsoft.MixedReality.Toolkit.Build.Editor.UnityPlayerBuildTools.StartCommandLineBuild + PathToProject: $(Build.Repository.LocalPath) + OutputPath: ${{ parameters.OutputPath }} + AdditionalArguments: -sceneList Assets/MRTK/Examples/Demos/HandTracking/Scenes/HandInteractionExamples.unity + +- task: PowerShell@2 + displayName: Validate build logs + inputs: + targetType: filePath + filePath: ./scripts/ci/validatebuildlog.ps1 + arguments: > + -LogFile $(Join-Path $(Agent.TempDirectory) "build_${{ parameters.BuildTarget }}.log") diff --git a/scripts/packaging/createupmpackages.ps1 b/scripts/packaging/createupmpackages.ps1 index d0ac7da5e3a..6df6a9ba9a0 100644 --- a/scripts/packaging/createupmpackages.ps1 +++ b/scripts/packaging/createupmpackages.ps1 @@ -18,24 +18,23 @@ Add this switch if ProjectRoot represents a folder with existing tarballs to be patched and repacked. #> param( + [Parameter(Mandatory = $true)] [string]$ProjectRoot, + [string]$OutputDirectory = "./artifacts/upm", - [ValidatePattern("^\d+\.\d+\.\d+-?[a-zA-Z0-9\.]*$")] + + [Parameter(Mandatory = $true)] + [ValidatePattern("^\d+\.\d+\.\d+$")] [string]$Version, + [ValidatePattern("^\d+?[\.\d+]*$")] [string]$PreviewNumber, + [switch]$Repack ) -if (-not $ProjectRoot) { - throw "Missing required parameter: -ProjectRoot." -} $ProjectRoot = Resolve-Path -Path $ProjectRoot -if (-not $Version) { - throw "Missing required parameter: -Version." -} - if ($PreviewNumber) { $Version = "$Version-preview.$PreviewNumber" } @@ -54,8 +53,8 @@ $product = "toolkit" # This hashtable contains mappings of the packages (by name) to the folder which contains # the package contents. # -# The keys of this hashtable will be combined with the scope and product to create the -# final name of the package (for example, com.microsoft.mixedreality.toolkit.foundation +# The keys of this hashtable will be combined with the scope and product to create the +# final name of the package (for example, com.microsoft.mixedreality.toolkit.foundation # will use the packaging file contained in the folder associated with the foundation key). # # Note that capitalization below in the key itself is significant. Capitalization @@ -63,12 +62,12 @@ $product = "toolkit" # # These paths are ProjectRoot relative. $packages = [ordered]@{ - "foundation" = "Assets/MRTK"; + "foundation" = "Assets/MRTK"; "standardassets" = "Assets/MRTK/StandardAssets"; - "extensions" = "Assets/MRTK/Extensions"; - "tools" = "Assets/MRTK/Tools"; - "testutilities" = "Assets/MRTK/Tests/TestUtilities"; - "examples" = "Assets/MRTK/Examples"; + "extensions" = "Assets/MRTK/Extensions"; + "tools" = "Assets/MRTK/Tools"; + "testutilities" = "Assets/MRTK/Tests/TestUtilities"; + "examples" = "Assets/MRTK/Examples"; } # Beginning of the upm packaging script main section @@ -185,7 +184,7 @@ foreach ($entry in $packages.GetEnumerator()) { # A samples folder was created. Remove it. Remove-Item -Path $samplesFolder -Recurse -Force } - + if ($packageName -eq "foundation") { # The foundation package MOVES some content around. This restores the moved files. Start-Process -FilePath "git" -ArgumentList "checkout */Services/SceneSystem/SceneSystemResources*" -NoNewWindow -Wait