diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index c5c60f3a09b..966aefd7914 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -14,15 +14,19 @@ jobs:
build:
name: build-${{ matrix.platform }}
# TRACE_CI_RUNNERS picks GitHub-hosted runners (unset) or the local fleet (`self-hosted`); see
- # docs/self-hosted-runners.md in Trace Arena. Under the flag only the legs the local fleet can host exist:
- # there is no Windows machine, and the arm64 Linux pool is a 1.5 GB container that cannot build the native
- # runtime. Hosted CI keeps all four legs.
- runs-on: ${{ vars.TRACE_CI_RUNNERS == 'self-hosted' && (matrix.platform == 'macos' && fromJSON('["self-hosted","macOS","ARM64"]') || fromJSON('["self-hosted","Linux","X64","yiazmat-linux-x64-native"]')) || (matrix.platform == 'windows' && 'windows-latest' || matrix.platform == 'macos' && 'macos-latest' || matrix.platform == 'linux-arm' && 'ubuntu-24.04-arm' || 'ubuntu-latest') }}
+ # docs/self-hosted-runners.md in Trace Arena. Under the flag the legs the local fleet can host exist: the Windows VM on the
+ # Linux server, the native x64 Linux server and the macOS machine. The arm64 Linux pool is a 1.5 GB container that cannot build
+ # the native runtime, so that leg stays hosted-only. Hosted CI keeps all four legs.
+ runs-on: ${{ vars.TRACE_CI_RUNNERS == 'self-hosted' && (matrix.platform == 'windows' && fromJSON('["self-hosted","Windows","X64"]') || matrix.platform == 'macos' && fromJSON('["self-hosted","macOS","ARM64"]') || fromJSON('["self-hosted","Linux","X64","yiazmat-linux-x64-native"]')) || (matrix.platform == 'windows' && 'windows-latest' || matrix.platform == 'macos' && 'macos-latest' || matrix.platform == 'linux-arm' && 'ubuntu-24.04-arm' || 'ubuntu-latest') }}
env:
- MONOGAME_WINDOWS_PLATFORM_TOOLSET: ${{ matrix.platform == 'windows' && 'v145' || '' }}
+ # The VSIX templates project needs the full Visual Studio IDE SDK, which the fleet's VM (Build Tools) does not have. The hosted
+ # legs keep building it.
+ MONOGAME_SKIP_VS_TEMPLATES: ${{ vars.TRACE_CI_RUNNERS == 'self-hosted' && matrix.platform == 'windows' && '1' || '' }}
+ # v145 ships with the newest Visual Studio; the fleet's Windows VM has VS 2022 Build Tools, whose toolset is v143.
+ MONOGAME_WINDOWS_PLATFORM_TOOLSET: ${{ matrix.platform == 'windows' && (vars.TRACE_CI_RUNNERS == 'self-hosted' && 'v143' || 'v145') || '' }}
strategy:
matrix:
- platform: ${{ fromJSON(vars.TRACE_CI_RUNNERS == 'self-hosted' && '["macos","linux"]' || '["windows","macos","linux","linux-arm"]') }}
+ platform: ${{ fromJSON(vars.TRACE_CI_RUNNERS == 'self-hosted' && '["windows","macos","linux"]' || '["windows","macos","linux","linux-arm"]') }}
fail-fast: false
defaults:
run:
diff --git a/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj b/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj
index 0b70c82ff3e..f2cf1637b29 100644
--- a/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj
+++ b/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj
@@ -141,7 +141,8 @@
/p:PlatformToolset=$(MONOGAME_WINDOWS_PLATFORM_TOOLSET)
-
+
+
diff --git a/Tools/MonoGame.Tools.Tests/BuilderTests.cs b/Tools/MonoGame.Tools.Tests/BuilderTests.cs
index 0bd604714e6..4f1bf444304 100644
--- a/Tools/MonoGame.Tools.Tests/BuilderTests.cs
+++ b/Tools/MonoGame.Tools.Tests/BuilderTests.cs
@@ -45,7 +45,10 @@ public void CommandLineParserTests()
Assert.AreEqual(MakePath(Directory.GetCurrentDirectory(), "obj\\Content"), args.RootedIntermediateDirectory);
args = ContentBuilderParams.Parse("build", "-s", "C:/This/Does/Not/Exist");
- Assert.AreEqual(MakePath("C:/This/Does/Not/Exist"), args.SourceDirectory);
+ // The parser stores the directory relative to the working directory. On a different drive it cannot, and the path stays
+ // absolute (the hosted runners work on D:); on the same drive it relativizes (the fleet's VM works on C:). Assert the
+ // round trip, not the hosted image's drive layout.
+ Assert.AreEqual(MakePath(Path.GetRelativePath(Directory.GetCurrentDirectory(), "C:/This/Does/Not/Exist")), args.SourceDirectory);
args = ContentBuilderParams.Parse(
"build",
diff --git a/build/BuildTemplatesTasks/BuildVSTemplatesTask.cs b/build/BuildTemplatesTasks/BuildVSTemplatesTask.cs
index 83f801ae24b..5749150295b 100644
--- a/build/BuildTemplatesTasks/BuildVSTemplatesTask.cs
+++ b/build/BuildTemplatesTasks/BuildVSTemplatesTask.cs
@@ -6,7 +6,10 @@ namespace BuildScripts;
[IsDependentOn(typeof(BuildDotNetTemplatesTask))]
public sealed class BuildVSTemplatesTask : FrostingTask
{
- public override bool ShouldRun(BuildContext context) => context.IsRunningOnWindows();
+ // The VSIX project needs the full Visual Studio IDE SDK (VSSDK1077: no extensions directory on a Build Tools-only machine).
+ // The workflow sets the variable for the self-hosted Windows VM, which has the Build Tools; the hosted legs keep building it.
+ public override bool ShouldRun(BuildContext context) =>
+ context.IsRunningOnWindows() && Environment.GetEnvironmentVariable("MONOGAME_SKIP_VS_TEMPLATES") != "1";
public override void Run(BuildContext context)
{
diff --git a/build/TestNuGetsTasks/TestMonoGameTemplateTaskBase.cs b/build/TestNuGetsTasks/TestMonoGameTemplateTaskBase.cs
index 6a462c1cfd3..bde48fbb40b 100644
--- a/build/TestNuGetsTasks/TestMonoGameTemplateTaskBase.cs
+++ b/build/TestNuGetsTasks/TestMonoGameTemplateTaskBase.cs
@@ -190,6 +190,25 @@ private void UninstallExistingTemplates(BuildContext context)
private void InstallTemplates(BuildContext context, string templateVersion, string nugetSourcePath)
{
+ // `dotnet new uninstall` removes the template but leaves its package in ~/.templateengine/packages, and the next
+ // `dotnet new install` of the same version fails with "File ... already exists" (templating exit code 106) instead of
+ // reinstalling. Clear the cached package so a rerun on the same machine starts from a clean template store.
+ var templateCache = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".templateengine", "packages");
+ if (Directory.Exists(templateCache))
+ {
+ foreach (var cached in Directory.GetFiles(templateCache, "MonoGame.Templates.CSharp.*.nupkg"))
+ {
+ try
+ {
+ File.Delete(cached);
+ }
+ catch (IOException)
+ {
+ // A package held open by another dotnet process: the install below will report it if it matters.
+ }
+ }
+ }
+
context.Information($"Installing MonoGame templates version {templateVersion}...");
context.StartProcess("dotnet", new ProcessSettings
{
diff --git a/build/Utils/StaticLibCheck.cs b/build/Utils/StaticLibCheck.cs
index 5eb0f408daf..ac656a3b1a2 100644
--- a/build/Utils/StaticLibCheck.cs
+++ b/build/Utils/StaticLibCheck.cs
@@ -48,7 +48,8 @@ public static class StaticLibCheck
public static void CheckWindows(BuildContext context, string filePath)
{
var vswhere = new VSWhereLatest(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools);
- var devcmdPath = vswhere.Latest(new VSWhereLatestSettings()).FullPath + @"\Common7\Tools\vsdevcmd.bat";
+ // Products = "*" so a Build Tools-only machine (the fleet's Windows VM) is found: the default product filter skips it.
+ var devcmdPath = vswhere.Latest(new VSWhereLatestSettings { Products = "*" }).FullPath + @"\Common7\Tools\vsdevcmd.bat";
context.StartProcess(
devcmdPath,