From 5f527dd6e919eb0380fa86401082aa0c58f6dc77 Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Wed, 2 Apr 2025 17:07:28 -0700
Subject: [PATCH 01/13] Send host tests to helix

---
 eng/pipelines/installer/steps/helix.yml | 18 ++++++++++++++++++
 eng/pipelines/runtime.yml               | 12 ++++++++++--
 src/installer/tests/helixpublish.proj   |  3 ++-
 3 files changed, 30 insertions(+), 3 deletions(-)
 create mode 100644 eng/pipelines/installer/steps/helix.yml

diff --git a/eng/pipelines/installer/steps/helix.yml b/eng/pipelines/installer/steps/helix.yml
new file mode 100644
index 00000000000000..269c88d264a010
--- /dev/null
+++ b/eng/pipelines/installer/steps/helix.yml
@@ -0,0 +1,18 @@
+parameters:
+  buildConfig: ''
+  archType: ''
+  osGroup: ''
+  targetRid: ''
+  creator: ''
+  helixQueues: ''
+
+steps:
+  - template: /eng/common/core-templates/steps/send-to-helix.yml
+    parameters:
+      DisplayNamePrefix: Send to Helix
+      HelixProjectPath: src/installer/tests/helixpublish.proj
+      HelixProjectArguments: /p:Configuration=${{ parameters.buildConfig }} /p:TargetArchitecture=${{ parameters.archType }} /p:TargetRuntimeIdentifier=${{ parameters.targetRid }} /p:TargetOS=${{ parameters.osGroup }}
+      HelixTargetQueues: ${{ join(';', parameters.helixQueues) }}
+      Creator: ${{ parameters.creator }}
+      ${{ if eq(variables['System.TeamProject'], 'internal') }}:
+        HelixAccessToken: $(HelixApiAccessToken)
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index 48d65de310e92f..c7d56acb9bc63e 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -1279,9 +1279,10 @@ extends:
           buildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
           platforms:
             - windows_x86
+          helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
           jobParameters:
             nameSuffix: Installer_Build_And_Test
-            buildArgs: -s host+packs -c $(_BuildConfig) -lc Release -rc Release -test
+            buildArgs: -s host+packs -c $(_BuildConfig) -lc Release -rc Release
             dependsOnGlobalBuilds:
               - nameSuffix: CoreCLR_Libraries
                 buildConfig: release
@@ -1298,6 +1299,9 @@ extends:
               - template: /eng/pipelines/installer/steps/upload-job-artifacts.yml
                 parameters:
                   name: $(osGroup)$(osSubgroup)_$(archType)
+              - template: /eng/pipelines/installer/steps/helix.yml
+                parameters:
+                  creator: dotnet-bot
             condition:
               or(
                 eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true),
@@ -1311,9 +1315,10 @@ extends:
             - windows_x64
             - osx_x64
             - linux_x64
+          helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
           jobParameters:
             nameSuffix: Installer_Build_And_Test
-            buildArgs: -s host+packs -c $(_BuildConfig) -lc ${{ variables.debugOnPrReleaseOnRolling }} -rc Release -test
+            buildArgs: -s host+packs -c $(_BuildConfig) -lc ${{ variables.debugOnPrReleaseOnRolling }} -rc Release
             dependsOnGlobalBuilds:
               - nameSuffix: CoreCLR_Libraries
                 buildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
@@ -1330,6 +1335,9 @@ extends:
               - template: /eng/pipelines/installer/steps/upload-job-artifacts.yml
                 parameters:
                   name: $(osGroup)$(osSubgroup)_$(archType)
+              - template: /eng/pipelines/installer/steps/helix.yml
+                parameters:
+                  creator: dotnet-bot
             condition:
               or(
                 eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true),
diff --git a/src/installer/tests/helixpublish.proj b/src/installer/tests/helixpublish.proj
index 7e1b1ee3baeef0..aa3e83a3ef61ec 100644
--- a/src/installer/tests/helixpublish.proj
+++ b/src/installer/tests/helixpublish.proj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.DotNet.Helix.Sdk">
+<Project Sdk="Microsoft.DotNet.Helix.Sdk" DefaultTargets="Test">
 
   <PropertyGroup>
     <HelixArchitecture>$(TargetArchitecture)</HelixArchitecture>
@@ -58,6 +58,7 @@
         <PayloadDirectory>%(HostTestProject.PayloadDirectory)</PayloadDirectory>
         <Command>%(HostTestProject.Command)</Command>
         <PreCommands>@(_HelixPreCommands)</PreCommands>
+        <Timeout>00:30:00</Timeout>
       </HelixWorkItem>
     </ItemGroup>
   </Target>

From 9047bd8e9ee25f54a7d5064ceefd351f7bb3b2e7 Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Thu, 3 Apr 2025 14:53:45 -0700
Subject: [PATCH 02/13] Remove TargetRuntimeIdentifier argument

---
 eng/pipelines/installer/steps/helix.yml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/eng/pipelines/installer/steps/helix.yml b/eng/pipelines/installer/steps/helix.yml
index 269c88d264a010..e276b2b859ee40 100644
--- a/eng/pipelines/installer/steps/helix.yml
+++ b/eng/pipelines/installer/steps/helix.yml
@@ -2,7 +2,6 @@ parameters:
   buildConfig: ''
   archType: ''
   osGroup: ''
-  targetRid: ''
   creator: ''
   helixQueues: ''
 
@@ -11,7 +10,7 @@ steps:
     parameters:
       DisplayNamePrefix: Send to Helix
       HelixProjectPath: src/installer/tests/helixpublish.proj
-      HelixProjectArguments: /p:Configuration=${{ parameters.buildConfig }} /p:TargetArchitecture=${{ parameters.archType }} /p:TargetRuntimeIdentifier=${{ parameters.targetRid }} /p:TargetOS=${{ parameters.osGroup }}
+      HelixProjectArguments: /p:Configuration=${{ parameters.buildConfig }} /p:TargetArchitecture=${{ parameters.archType }} /p:TargetOS=${{ parameters.osGroup }}
       HelixTargetQueues: ${{ join(';', parameters.helixQueues) }}
       Creator: ${{ parameters.creator }}
       ${{ if eq(variables['System.TeamProject'], 'internal') }}:

From d0ec20a517d8c87a187ad6827d243a4ea2386295 Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Fri, 4 Apr 2025 10:40:24 -0700
Subject: [PATCH 03/13] Add installer/helix-queues-setup.yml

---
 .../installer/helix-queues-setup.yml          | 66 +++++++++++++++++++
 eng/pipelines/installer/steps/helix.yml       |  6 +-
 eng/pipelines/runtime.yml                     |  4 +-
 3 files changed, 72 insertions(+), 4 deletions(-)
 create mode 100644 eng/pipelines/installer/helix-queues-setup.yml

diff --git a/eng/pipelines/installer/helix-queues-setup.yml b/eng/pipelines/installer/helix-queues-setup.yml
new file mode 100644
index 00000000000000..94f234527d4f99
--- /dev/null
+++ b/eng/pipelines/installer/helix-queues-setup.yml
@@ -0,0 +1,66 @@
+parameters:
+  jobTemplate: ''
+  variables: []
+  osGroup: ''
+  osSubgroup: ''
+  archType: ''
+  container: ''
+  pool: ''
+  platform: ''
+  shouldContinueOnError: false
+  jobParameters: {}
+
+jobs:
+- template: ${{ parameters.jobTemplate }}
+  parameters:
+    variables: ${{ parameters.variables }}
+    osGroup: ${{ parameters.osGroup }}
+    osSubgroup: ${{ parameters.osSubgroup }}
+    archType: ${{ parameters.archType }}
+    container: ${{ parameters.container }}
+    pool: ${{ parameters.pool }}
+    platform: ${{ parameters.platform }}
+    shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
+    helixQueues:
+
+    # Linux arm
+    - ${{ if eq(parameters.platform, 'linux_arm') }}:
+      - (Debian.12.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-arm32v7
+
+    # Linux arm64
+    - ${{ if eq(parameters.platform, 'linux_arm64') }}:
+      - (Ubuntu.2404.Arm64.Open)Ubuntu.2204.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-24.04-helix-arm64v8
+
+    # Linux musl x64
+    - ${{ if eq(parameters.platform, 'linux_musl_x64') }}:
+      - (Alpine.321.Amd64.Open)azurelinux.3.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-amd64
+
+    # Linux musl arm64
+    - ${{ if and(eq(parameters.platform, 'linux_musl_arm64'), or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true))) }}:
+      - (Alpine.321.Arm64.Open)ubuntu.2204.armarch.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-arm64v8
+
+    # Linux x64
+    - ${{ if eq(parameters.platform, 'linux_x64') }}:
+      - azurelinux.3.amd64.open
+
+    # OSX arm64
+    - ${{ if eq(parameters.platform, 'osx_arm64') }}:
+      - osx.13.arm64.open
+
+    # OSX x64
+    - ${{ if eq(parameters.platform, 'osx_x64') }}:
+      - OSX.1200.Amd64.Open
+
+    # windows x64
+    - ${{ if eq(parameters.platform, 'windows_x64') }}:
+      - Windows.11.Amd64.Client.Open
+
+    # windows x86
+    - ${{ if eq(parameters.platform, 'windows_x86') }}:
+      - Windows.11.Amd64.Client.Open
+
+    # windows arm64
+    - ${{ if eq(parameters.platform, 'windows_arm64') }}:
+      - Windows.11.Arm64.Open
+
+    ${{ insert }}: ${{ parameters.jobParameters }}
diff --git a/eng/pipelines/installer/steps/helix.yml b/eng/pipelines/installer/steps/helix.yml
index e276b2b859ee40..9a818484736d3d 100644
--- a/eng/pipelines/installer/steps/helix.yml
+++ b/eng/pipelines/installer/steps/helix.yml
@@ -6,12 +6,14 @@ parameters:
   helixQueues: ''
 
 steps:
-  - template: /eng/common/core-templates/steps/send-to-helix.yml
+  - template: /eng/common/templates/steps/send-to-helix.yml
     parameters:
       DisplayNamePrefix: Send to Helix
       HelixProjectPath: src/installer/tests/helixpublish.proj
       HelixProjectArguments: /p:Configuration=${{ parameters.buildConfig }} /p:TargetArchitecture=${{ parameters.archType }} /p:TargetOS=${{ parameters.osGroup }}
-      HelixTargetQueues: ${{ join(';', parameters.helixQueues) }}
       Creator: ${{ parameters.creator }}
       ${{ if eq(variables['System.TeamProject'], 'internal') }}:
         HelixAccessToken: $(HelixApiAccessToken)
+        HelixTargetQueues: ${{ replace(lower(join('+', parameters.helixQueues)), '.open', '') }}
+      ${{ if eq(variables['System.TeamProject'], 'public') }}:
+        HelixTargetQueues: ${{ join('+', parameters.helixQueues) }}
\ No newline at end of file
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index c7d56acb9bc63e..057973e02bffc2 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -1279,7 +1279,7 @@ extends:
           buildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
           platforms:
             - windows_x86
-          helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
+          helixQueuesTemplate: /eng/pipelines/installer/helix-queues-setup.yml
           jobParameters:
             nameSuffix: Installer_Build_And_Test
             buildArgs: -s host+packs -c $(_BuildConfig) -lc Release -rc Release
@@ -1315,7 +1315,7 @@ extends:
             - windows_x64
             - osx_x64
             - linux_x64
-          helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
+          helixQueuesTemplate: /eng/pipelines/installer/helix-queues-setup.yml
           jobParameters:
             nameSuffix: Installer_Build_And_Test
             buildArgs: -s host+packs -c $(_BuildConfig) -lc ${{ variables.debugOnPrReleaseOnRolling }} -rc Release

From 4f632960e23c25981c0c7cf6747a9ffb59d368b7 Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Fri, 4 Apr 2025 10:57:16 -0700
Subject: [PATCH 04/13] Add TestRunNamePrefix

---
 src/installer/tests/helixpublish.proj | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/installer/tests/helixpublish.proj b/src/installer/tests/helixpublish.proj
index aa3e83a3ef61ec..bf8d4905a84314 100644
--- a/src/installer/tests/helixpublish.proj
+++ b/src/installer/tests/helixpublish.proj
@@ -6,6 +6,7 @@
     <HelixBuild Condition="'$(HelixBuild)' == ''">default</HelixBuild>
     <HelixConfiguration>$(Configuration)</HelixConfiguration>
     <HelixType>test/host</HelixType>
+    <TestRunNamePrefix>host-$(TargetOS)-$(TargetArchitecture)-$(Configuration) @ </TestRunNamePrefix>
 
     <IncludeDotNetCli>true</IncludeDotNetCli>
     <DotNetCliPackageType>sdk</DotNetCliPackageType>

From d9105c6920a0ae01cefeaa9b991b1de6e96b38b5 Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Fri, 4 Apr 2025 10:57:30 -0700
Subject: [PATCH 05/13] Use matching build config

---
 eng/pipelines/installer/steps/helix.yml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/eng/pipelines/installer/steps/helix.yml b/eng/pipelines/installer/steps/helix.yml
index 9a818484736d3d..a8bed247bfd336 100644
--- a/eng/pipelines/installer/steps/helix.yml
+++ b/eng/pipelines/installer/steps/helix.yml
@@ -1,5 +1,4 @@
 parameters:
-  buildConfig: ''
   archType: ''
   osGroup: ''
   creator: ''
@@ -10,7 +9,7 @@ steps:
     parameters:
       DisplayNamePrefix: Send to Helix
       HelixProjectPath: src/installer/tests/helixpublish.proj
-      HelixProjectArguments: /p:Configuration=${{ parameters.buildConfig }} /p:TargetArchitecture=${{ parameters.archType }} /p:TargetOS=${{ parameters.osGroup }}
+      HelixProjectArguments: -ci /p:Configuration=$(_BuildConfig) /p:TargetArchitecture=${{ parameters.archType }} /p:TargetOS=${{ parameters.osGroup }}
       Creator: ${{ parameters.creator }}
       ${{ if eq(variables['System.TeamProject'], 'internal') }}:
         HelixAccessToken: $(HelixApiAccessToken)

From 02b3e81e18426e43daaad227d5c7f04e4ea4618e Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Fri, 4 Apr 2025 13:34:48 -0700
Subject: [PATCH 06/13] Fix ci arg, unnecessary parameters, timeout

---
 eng/pipelines/installer/steps/helix.yml | 6 +++++-
 eng/pipelines/runtime.yml               | 6 ++----
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/eng/pipelines/installer/steps/helix.yml b/eng/pipelines/installer/steps/helix.yml
index a8bed247bfd336..a446c43fb53dec 100644
--- a/eng/pipelines/installer/steps/helix.yml
+++ b/eng/pipelines/installer/steps/helix.yml
@@ -9,7 +9,11 @@ steps:
     parameters:
       DisplayNamePrefix: Send to Helix
       HelixProjectPath: src/installer/tests/helixpublish.proj
-      HelixProjectArguments: -ci /p:Configuration=$(_BuildConfig) /p:TargetArchitecture=${{ parameters.archType }} /p:TargetOS=${{ parameters.osGroup }}
+      HelixProjectArguments: >
+        /p:Configuration=$(_BuildConfig)
+        /p:TargetArchitecture=${{ parameters.archType }}
+        /p:TargetOS=${{ parameters.osGroup }}
+        /p:ContinuousIntegrationBuild=true
       Creator: ${{ parameters.creator }}
       ${{ if eq(variables['System.TeamProject'], 'internal') }}:
         HelixAccessToken: $(HelixApiAccessToken)
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index 057973e02bffc2..7f5288b4d8f8c7 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -1293,8 +1293,7 @@ extends:
                   artifactFileName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_Release$(archiveExtension)
                   unpackFolder: $(Build.SourcesDirectory)/artifacts/bin
                   displayName: 'unified artifacts'
-            enablePublishTestResults: true
-            testRunTitle: Installer-$(osGroup)$(osSubgroup)_$(archType)
+            timeoutInMinutes: 120
             postBuildSteps:
               - template: /eng/pipelines/installer/steps/upload-job-artifacts.yml
                 parameters:
@@ -1329,8 +1328,7 @@ extends:
                   artifactFileName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(debugOnPrReleaseOnRolling)$(archiveExtension)
                   unpackFolder: $(Build.SourcesDirectory)/artifacts/bin
                   displayName: 'unified artifacts'
-            enablePublishTestResults: true
-            testRunTitle: Installer-$(osGroup)$(osSubgroup)_$(archType)
+            timeoutInMinutes: 120
             postBuildSteps:
               - template: /eng/pipelines/installer/steps/upload-job-artifacts.yml
                 parameters:

From 7ab50b4d77ddfce35fa92675d6adf0852377e6ff Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Mon, 7 Apr 2025 11:07:28 -0700
Subject: [PATCH 07/13] Remove extra line break

---
 eng/pipelines/installer/steps/helix.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eng/pipelines/installer/steps/helix.yml b/eng/pipelines/installer/steps/helix.yml
index a446c43fb53dec..1183ca669dcc4c 100644
--- a/eng/pipelines/installer/steps/helix.yml
+++ b/eng/pipelines/installer/steps/helix.yml
@@ -9,7 +9,7 @@ steps:
     parameters:
       DisplayNamePrefix: Send to Helix
       HelixProjectPath: src/installer/tests/helixpublish.proj
-      HelixProjectArguments: >
+      HelixProjectArguments: >-
         /p:Configuration=$(_BuildConfig)
         /p:TargetArchitecture=${{ parameters.archType }}
         /p:TargetOS=${{ parameters.osGroup }}

From c1ecb30565be10e01e93b4283ac7427b9b54cad0 Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Mon, 7 Apr 2025 11:07:39 -0700
Subject: [PATCH 08/13] Resolve test artifacts path on macOS (/tmp/ symlink)

---
 src/installer/tests/TestUtils/TestContext.cs | 22 ++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/src/installer/tests/TestUtils/TestContext.cs b/src/installer/tests/TestUtils/TestContext.cs
index 6f0afbff217d89..24bbaebc0ca84d 100644
--- a/src/installer/tests/TestUtils/TestContext.cs
+++ b/src/installer/tests/TestUtils/TestContext.cs
@@ -42,8 +42,8 @@ static TestContext()
             MicrosoftNETCoreAppVersion = GetTestContextVariable("MNA_VERSION");
             Tfm = GetTestContextVariable("MNA_TFM");
 
-            TestAssetsOutput = GetTestContextVariable("TEST_ASSETS_OUTPUT");
-            TestArtifactsPath = GetTestContextVariable("TEST_ARTIFACTS");
+            TestAssetsOutput = ResolveTestContextPath(GetTestContextVariable("TEST_ASSETS_OUTPUT"));
+            TestArtifactsPath = ResolveTestContextPath(GetTestContextVariable("TEST_ARTIFACTS"));
             Directory.CreateDirectory(TestArtifactsPath);
 
             // Create an empty global.json, so running tests from test artifacts is not affected
@@ -68,5 +68,23 @@ public static string GetTestContextVariable(string name)
 
             throw new ArgumentException($"Unable to find variable '{name}' in test context variable file '{_testContextVariableFilePath}'");
         }
+
+        private static string ResolveTestContextPath(string path)
+        {
+            // On macOS, /tmp/ is a symlink. Running apps out of it will resolve the path, so determine the resolved path here.
+            if (!OperatingSystem.IsMacOS())
+                return path;
+
+            string tmpPath = "/tmp/";
+            if (!path.StartsWith(tmpPath))
+                return path;
+
+            // No trailing slash in order to properly check the link target
+            DirectoryInfo tmp = new DirectoryInfo(tmpPath[..^1]);
+            if (tmp.LinkTarget == null)
+                return path;
+
+            return Path.Combine(tmp.ResolveLinkTarget(true).FullName, path[tmpPath.Length..]);
+        }
     }
 }

From ecda08c9a808921a1f3670b24943941a31321f5a Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Mon, 7 Apr 2025 14:06:25 -0700
Subject: [PATCH 09/13] Use ci script arg

---
 eng/pipelines/installer/steps/helix.yml | 17 ++++++++++++-----
 eng/pipelines/runtime.yml               |  4 ++--
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/eng/pipelines/installer/steps/helix.yml b/eng/pipelines/installer/steps/helix.yml
index 1183ca669dcc4c..6812c87c318dc8 100644
--- a/eng/pipelines/installer/steps/helix.yml
+++ b/eng/pipelines/installer/steps/helix.yml
@@ -9,11 +9,18 @@ steps:
     parameters:
       DisplayNamePrefix: Send to Helix
       HelixProjectPath: src/installer/tests/helixpublish.proj
-      HelixProjectArguments: >-
-        /p:Configuration=$(_BuildConfig)
-        /p:TargetArchitecture=${{ parameters.archType }}
-        /p:TargetOS=${{ parameters.osGroup }}
-        /p:ContinuousIntegrationBuild=true
+      ${{ if ne(parameters.osGroup, 'windows') }}:
+        HelixProjectArguments: >-
+          --ci
+          /p:Configuration=$(_BuildConfig)
+          /p:TargetArchitecture=${{ parameters.archType }}
+          /p:TargetOS=${{ parameters.osGroup }}
+      ${{ if eq(parameters.osGroup, 'windows') }}:
+        HelixProjectArguments: >-
+          -ci
+          /p:Configuration=$(_BuildConfig)
+          /p:TargetArchitecture=${{ parameters.archType }}
+          /p:TargetOS=${{ parameters.osGroup }}
       Creator: ${{ parameters.creator }}
       ${{ if eq(variables['System.TeamProject'], 'internal') }}:
         HelixAccessToken: $(HelixApiAccessToken)
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index 7f5288b4d8f8c7..fa4a2dcdd7da50 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -1293,7 +1293,7 @@ extends:
                   artifactFileName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_Release$(archiveExtension)
                   unpackFolder: $(Build.SourcesDirectory)/artifacts/bin
                   displayName: 'unified artifacts'
-            timeoutInMinutes: 120
+            timeoutInMinutes: 150
             postBuildSteps:
               - template: /eng/pipelines/installer/steps/upload-job-artifacts.yml
                 parameters:
@@ -1328,7 +1328,7 @@ extends:
                   artifactFileName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(debugOnPrReleaseOnRolling)$(archiveExtension)
                   unpackFolder: $(Build.SourcesDirectory)/artifacts/bin
                   displayName: 'unified artifacts'
-            timeoutInMinutes: 120
+            timeoutInMinutes: 150
             postBuildSteps:
               - template: /eng/pipelines/installer/steps/upload-job-artifacts.yml
                 parameters:

From d1af6cb83a18b739be25e15cb9faf008e2795a15 Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Mon, 7 Apr 2025 14:44:33 -0700
Subject: [PATCH 10/13] Remove unnecessary post-build step

---
 eng/pipelines/installer/{steps => }/helix.yml |  0
 .../installer/steps/upload-job-artifacts.yml  | 26 -------------------
 eng/pipelines/runtime.yml                     | 10 ++-----
 3 files changed, 2 insertions(+), 34 deletions(-)
 rename eng/pipelines/installer/{steps => }/helix.yml (100%)
 delete mode 100644 eng/pipelines/installer/steps/upload-job-artifacts.yml

diff --git a/eng/pipelines/installer/steps/helix.yml b/eng/pipelines/installer/helix.yml
similarity index 100%
rename from eng/pipelines/installer/steps/helix.yml
rename to eng/pipelines/installer/helix.yml
diff --git a/eng/pipelines/installer/steps/upload-job-artifacts.yml b/eng/pipelines/installer/steps/upload-job-artifacts.yml
deleted file mode 100644
index 076f989780bbfe..00000000000000
--- a/eng/pipelines/installer/steps/upload-job-artifacts.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-parameters:
-  name: ''
-
-steps:
-# Upload binaries and symbols on failure to allow debugging issues
-- task: CopyFiles@2
-  displayName: Prepare binaries to publish
-  inputs:
-    SourceFolder: '$(Build.SourcesDirectory)/artifacts/bin'
-    Contents: |
-      */corehost/**
-      */corehost_test/**
-    TargetFolder: '$(Build.StagingDirectory)/Binaries'
-  continueOnError: true
-  condition: failed()
-
-- template: /eng/pipelines/common/upload-artifact-step.yml
-  parameters:
-    rootFolder: '$(Build.StagingDirectory)/Binaries'
-    includeRootFolder: false
-    archiveType: $(archiveType)
-    archiveExtension: $(archiveExtension)
-    tarCompression: $(tarCompression)
-    artifactName: 'Installer-Binaries-${{ parameters.name }}-$(_BuildConfig)'
-    displayName: 'Binaries'
-    condition: failed()
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index fa4a2dcdd7da50..dcaedbb7b15b55 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -1295,10 +1295,7 @@ extends:
                   displayName: 'unified artifacts'
             timeoutInMinutes: 150
             postBuildSteps:
-              - template: /eng/pipelines/installer/steps/upload-job-artifacts.yml
-                parameters:
-                  name: $(osGroup)$(osSubgroup)_$(archType)
-              - template: /eng/pipelines/installer/steps/helix.yml
+              - template: /eng/pipelines/installer/helix.yml
                 parameters:
                   creator: dotnet-bot
             condition:
@@ -1330,10 +1327,7 @@ extends:
                   displayName: 'unified artifacts'
             timeoutInMinutes: 150
             postBuildSteps:
-              - template: /eng/pipelines/installer/steps/upload-job-artifacts.yml
-                parameters:
-                  name: $(osGroup)$(osSubgroup)_$(archType)
-              - template: /eng/pipelines/installer/steps/helix.yml
+              - template: /eng/pipelines/installer/helix.yml
                 parameters:
                   creator: dotnet-bot
             condition:

From 0a51e0bce2b4510398681df0a1f29da4ddcf3c54 Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Tue, 8 Apr 2025 12:18:27 -0700
Subject: [PATCH 11/13] Specific trx and results directory for test result
 reporting

---
 src/installer/tests/helixpublish.proj | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/installer/tests/helixpublish.proj b/src/installer/tests/helixpublish.proj
index bf8d4905a84314..3db775f566567b 100644
--- a/src/installer/tests/helixpublish.proj
+++ b/src/installer/tests/helixpublish.proj
@@ -47,7 +47,7 @@
     </MSBuild>
     <ItemGroup>
       <HostTestProject>
-        <Command>dotnet test $([System.IO.Path]::GetFileName($(_TargetPath))) $(TestRunnerAdditionalArguments)</Command>
+        <Command>dotnet test $([System.IO.Path]::GetFileName($(_TargetPath))) $(TestRunnerAdditionalArguments) --logger trx --results-directory .</Command>
         <PayloadDirectory>$(_PayloadDirectory)</PayloadDirectory>
       </HostTestProject>
     </ItemGroup>

From 2051a3d54a734b16691090e614a1ff3af3c8917c Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Tue, 8 Apr 2025 12:18:59 -0700
Subject: [PATCH 12/13] Copy debug CRT for IJW test

---
 .../HostActivation.Tests/NativeHosting/Ijwhost.cs    | 10 +++++++++-
 src/native/corehost/test/ijw/CMakeLists.txt          | 12 ++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/installer/tests/HostActivation.Tests/NativeHosting/Ijwhost.cs b/src/installer/tests/HostActivation.Tests/NativeHosting/Ijwhost.cs
index fa00b0419a85ef..b77b77d691e52b 100644
--- a/src/installer/tests/HostActivation.Tests/NativeHosting/Ijwhost.cs
+++ b/src/installer/tests/HostActivation.Tests/NativeHosting/Ijwhost.cs
@@ -154,9 +154,17 @@ public SharedTestState()
                 string ijwhostName = "ijwhost.dll";
                 File.Copy(Path.Combine(RepoDirectoriesProvider.Default.HostArtifacts, ijwhostName), Path.Combine(folder, ijwhostName));
 
-                // Copy over the C++/CLI test library
+                // Copy over the C++/CLI test library and any dependencies
                 string ijwLibraryName = "ijw.dll";
                 File.Copy(Path.Combine(RepoDirectoriesProvider.Default.HostTestArtifacts, ijwLibraryName), Path.Combine(folder, ijwLibraryName));
+                string ijwDependencies = Path.Combine(RepoDirectoriesProvider.Default.HostTestArtifacts, "ijw-deps");
+                if (Directory.Exists(ijwDependencies))
+                {
+                    foreach(string file in Directory.GetFiles(ijwDependencies))
+                    {
+                        File.Copy(file, Path.Combine(folder, Path.GetFileName(file)));
+                    }
+                }
 
                 // Create a runtimeconfig.json for the C++/CLI test library
                 new RuntimeConfig(Path.Combine(folder, "ijw.runtimeconfig.json"))
diff --git a/src/native/corehost/test/ijw/CMakeLists.txt b/src/native/corehost/test/ijw/CMakeLists.txt
index 9fbd72412d4c8e..902e6a225767a0 100644
--- a/src/native/corehost/test/ijw/CMakeLists.txt
+++ b/src/native/corehost/test/ijw/CMakeLists.txt
@@ -10,3 +10,15 @@ remove_ijw_incompatible_target_options(ijw)
 add_ijw_msbuild_project_properties(ijw ijwhost)
 
 install_with_stripped_symbols(ijw TARGETS corehost_test)
+
+if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+  # Copy over the debug CRT so that it is available for test runs
+  file(
+    GLOB_RECURSE
+    DEBUG_CRT_FILES
+    $ENV{VCToolsRedistDir}/onecore/debug_nonredist/${ARCH_TARGET_NAME}/Microsoft.VC*.DebugCRT/vcruntime*d.dll
+    $ENV{VCToolsRedistDir}/onecore/debug_nonredist/${ARCH_TARGET_NAME}/Microsoft.VC*.DebugCRT/msvcp*d.dll
+    $ENV{ExtensionSdkDir}/Microsoft.UniversalCRT.Debug/$ENV{UCRTVersion}/Redist/Debug/${ARCH_TARGET_NAME}/ucrtbased.dll
+  )
+  install(FILES ${DEBUG_CRT_FILES} DESTINATION corehost_test/ijw-deps)
+endif ()
\ No newline at end of file

From 4670af374902360d74fbbc4c289cac3217706b8d Mon Sep 17 00:00:00 2001
From: Elinor Fung <elfung@microsoft.com>
Date: Thu, 10 Apr 2025 21:32:53 -0700
Subject: [PATCH 13/13] Add retry for test file backup restore

---
 .../tests/TestUtils/TestFileBackup.cs         | 63 ++++++++++++-------
 1 file changed, 42 insertions(+), 21 deletions(-)

diff --git a/src/installer/tests/TestUtils/TestFileBackup.cs b/src/installer/tests/TestUtils/TestFileBackup.cs
index b9f50d9ea97d32..ffc7d62946ad80 100644
--- a/src/installer/tests/TestUtils/TestFileBackup.cs
+++ b/src/installer/tests/TestUtils/TestFileBackup.cs
@@ -76,28 +76,13 @@ public void Dispose()
                 // This is a known problem where the actual Delete call is not 100% synchronous
                 // the OS reports a success but the file/folder is not fully removed yet.
                 // So implement a simple retry with a short timeout.
-                IOException exception = null;
-                for (int retryCount = 5; retryCount > 0; retryCount--)
-                {
-                    try
+                RetryOnIOError(() =>
                     {
                         Directory.Delete(_backupPath, recursive: true);
-                        if (!Directory.Exists(_backupPath))
-                        {
-                            return;
-                        }
-                    }
-                    catch (IOException ex)
-                    {
-                        exception = ex;
-                    }
-
-                    System.Threading.Thread.Sleep(200);
-                }
-                
-                throw new Exception(
-                    $"Failed to delete the backup folder {_backupPath} even after retries.\r\n"
-                    + (exception == null ? "" : exception.ToString()));
+                        return !Directory.Exists(_backupPath);
+                    },
+                    $"Failed to delete the backup folder {_backupPath} even after retries."
+                );
             }
         }
 
@@ -110,8 +95,44 @@ private static void CopyOverDirectory(string source, string destination)
 
             foreach (string file in Directory.GetFiles(source))
             {
-                File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), overwrite: true);
+                // Some files may still be reported as in use my the OS - for example immediately after
+                // process exit. Simple retry to separate this case from a file being intentionally locked.
+                RetryOnIOError(() =>
+                    {
+                        File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), overwrite: true);
+                        return true;
+                    },
+                    $"Failed to restore file {Path.GetFileName(file)}"
+                );
             }
         }
+
+        private static void RetryOnIOError(Func<bool> action, string errorMessage, int maxRetries = 5)
+        {
+            IOException exception = null;
+            for (int i = 0; i < maxRetries; i++)
+            {
+                try
+                {
+                    if (action())
+                    {
+                        return;
+                    }
+                }
+                catch (IOException e) 
+                {
+                    exception = e;
+                }
+
+                System.Threading.Thread.Sleep(200);
+            }
+
+            throw new Exception(
+                $"""
+                {errorMessage}
+                {(exception == null ? "" : exception.ToString())}
+                """);
+
+        }
     }
 }
