From f3ff8e6ad1ac2e9fbc55ad8f887649f629743f72 Mon Sep 17 00:00:00 2001 From: Kevin Martinez Date: Fri, 13 Nov 2026 11:46:52 -0500 Subject: [PATCH 1/2] fix(cli): resolve the runtime pack with the desktop publish properties A demo's publish moves its restore output to obj/package/ (MicroEngineNativePackage); the runtime pack query ran without that property and read obj/, which a fresh checkout lacks, so every native package job of the nightly validation failed with NETSDK1004. --- src/MicroEngine.Cli/Packaging.cs | 16 ++++++--- tests/MicroEngine.Cli.Tests/NoticesTests.cs | 37 +++++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/MicroEngine.Cli/Packaging.cs b/src/MicroEngine.Cli/Packaging.cs index 66aedbca..6f5239fd 100644 --- a/src/MicroEngine.Cli/Packaging.cs +++ b/src/MicroEngine.Cli/Packaging.cs @@ -65,6 +65,13 @@ private string Required(string name) /// application bundle. public static class Packaging { + /// The MSBuild properties of a desktop package's publish, given to every MSBuild call about that publish. + public static readonly string[] DesktopPublishProperties = + [ + "-p:PublishSingleFile=true", "-p:EnableCompressionInSingleFile=true", "-p:MicroEngineNativePackage=true", "-p:DebugType=none", + "-p:DebugSymbols=false", "-p:InvariantGlobalization=true", "-p:PublishDocumentationFiles=false", "-p:PublishReferencesDocumentationFiles=false", + ]; + public static async Task Desktop(PackageRequest request) { var (game, t) = (request.Game, request.Target); @@ -79,9 +86,8 @@ public static async Task Desktop(PackageRequest request) { string publish = Path.Combine(stage, "publish"); Console.WriteLine($"Publishing {game.Title} for {t.Label}..."); - Tool.Run(Tool.Dotnet, ["publish", game.Path, "-c", "Release", "-r", t.Rid, "--self-contained", "-p:PublishSingleFile=true", - "-p:EnableCompressionInSingleFile=true", "-p:MicroEngineNativePackage=true", "-p:DebugType=none", "-p:DebugSymbols=false", - "-p:InvariantGlobalization=true", "-p:PublishDocumentationFiles=false", "-p:PublishReferencesDocumentationFiles=false", "-o", publish, "-nologo"], game.Directory, "dotnet publish"); + Tool.Run(Tool.Dotnet, ["publish", game.Path, "-c", "Release", "-r", t.Rid, "--self-contained", .. DesktopPublishProperties, "-o", publish, "-nologo"], + game.Directory, "dotnet publish"); string top = Path.Combine(stage, game.Id); Directory.CreateDirectory(top); string exe = t.Name == "windows" ? $"{game.Id}.exe" : game.Id; @@ -111,7 +117,9 @@ public static async Task Desktop(PackageRequest request) File.WriteAllText(Path.Combine(top, $"{desktopId}.desktop"), DesktopEntry(game, icon is not null)); } } - var runtime = RuntimePack(game.Path, t.Rid); + // The same properties as the publish: one of them may move the project's restore output (a game's own + // Directory.Build.props can put it under another obj folder), and the query reads that output. + var runtime = RuntimePack(game.Path, t.Rid, DesktopPublishProperties); var info = BuildInfo(request, signing, runtime.Version); WriteCommon(top, game, t, runtime, info); Directory.CreateDirectory(request.Out); diff --git a/tests/MicroEngine.Cli.Tests/NoticesTests.cs b/tests/MicroEngine.Cli.Tests/NoticesTests.cs index 539a0c79..9ef4a2f0 100644 --- a/tests/MicroEngine.Cli.Tests/NoticesTests.cs +++ b/tests/MicroEngine.Cli.Tests/NoticesTests.cs @@ -61,6 +61,43 @@ public void The_runtime_licences_come_from_the_runtime_pack_MSBuild_resolved_not Assert.ThrowsExactly(() => Packaging.ParseRuntimePack("warning: not JSON")); } + [TestMethod] + public void The_runtime_pack_is_resolved_with_the_publish_properties_that_move_the_restore_output() + { + // As in the repository's demos: a publish property moves the restore output to obj/package/. Resolving the runtime + // pack without that property reads obj/, which a fresh checkout does not have. + string dir = Directory.CreateTempSubdirectory("microengine-runtime-pack-").FullName; + try + { + File.WriteAllText(Path.Combine(dir, "Directory.Build.props"), """ + + + obj/package/ + + + """); + string project = Path.Combine(dir, "Game.csproj"); + File.WriteAllText(project, """ + + Exenet10.0 + + """); + string rid = System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier; + Tool.Run(Tool.Dotnet, ["restore", project, "-r", rid, "-p:SelfContained=true", .. Packaging.DesktopPublishProperties, "-nologo"], dir, "restore"); + Assert.IsFalse(File.Exists(Path.Combine(dir, "obj", "project.assets.json")), "the restore output is under obj/package/ only"); + Assert.IsTrue(File.Exists(Path.Combine(dir, "obj", "package", "project.assets.json"))); + + var runtime = Packaging.RuntimePack(project, rid, Packaging.DesktopPublishProperties); + StringAssert.StartsWith(runtime.Version, "10.0."); + Assert.IsTrue(Directory.Exists(runtime.Directory), runtime.Directory); + Assert.ThrowsExactly(() => Packaging.RuntimePack(project, rid), "without the properties MSBuild reads obj/, which has no restore output"); + } + finally + { + Directory.Delete(dir, recursive: true); + } + } + [TestMethod] public void A_runtime_pack_without_its_licence_files_is_an_error_that_names_the_folder() { From acff5b472e2d2044003b25c3d511a7e50c15b472 Mon Sep 17 00:00:00 2001 From: Kevin Martinez Date: Fri, 13 Nov 2026 11:48:18 -0500 Subject: [PATCH 2/2] docs(release-notes): list the runtime pack fix under the next release --- docs/guide/release-notes.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/guide/release-notes.md b/docs/guide/release-notes.md index 9ab2fa32..5432c0f7 100644 --- a/docs/guide/release-notes.md +++ b/docs/guide/release-notes.md @@ -4,6 +4,15 @@ One section per SDK version, newest first. The SDK is in Alpha: a version may ch every such change is in the [migration notes](../migrations.md). Releases are tagged `sdk-v`; the demo releases (`v0.1.0`, `v0.2.0`...) are separate. +## Next release + +**Fixed** + +- `microengine package windows`, `linux` and `macos` stopped with `NETSDK1004` ("assets file not found") for a game + whose `Directory.Build.props` moves the restore output when the package's publish properties are set: the tool + looked for the .NET runtime pack the build used without those properties. It now reads it with the same properties + as the publish. + ## 0.6.0-alpha.1 An eighth package: `MicroEngine.Physics.Box2D`, optional, for dynamic bodies. Diagnostics for finding out why a game