3 Commits

Author SHA1 Message Date
gamer147
258c42618b Preserve Godot UID across OME rename
All checks were successful
Core validation / Linux core gate (push) Successful in 1m12s
Release builds / Linux x64 artifact (push) Successful in 1m21s
Release builds / Windows x64 artifact (push) Successful in 1m15s
Release builds / Publish tagged Gitea release (push) Successful in 22s
2026-08-18 11:26:36 -04:00
gamer147
eeecd1edba Fix pruned FFmpeg release inputs
Some checks failed
Core validation / Linux core gate (push) Successful in 56s
Release builds / Linux x64 artifact (push) Successful in 1m23s
Release builds / Windows x64 artifact (push) Successful in 1m15s
Release builds / Publish tagged Gitea release (push) Failing after 19s
2026-08-18 09:17:54 -04:00
gamer147
3a076e2781 Constrain core validation memory usage
Some checks failed
Core validation / Linux core gate (push) Successful in 55s
Release builds / Linux x64 artifact (push) Failing after 39s
Release builds / Windows x64 artifact (push) Failing after 48s
Release builds / Publish tagged Gitea release (push) Has been skipped
2026-08-18 09:00:42 -04:00
11 changed files with 164 additions and 32 deletions

View File

@@ -221,8 +221,10 @@ VM op 0x236 (non-modal) / op 0x20f (modal) / op 0x24d (green-mask transition)
Everything before and after the selected decoder is portable. The replacement decision is an in-process
FFmpeg backend behind a project-owned C ABI, not raw FFmpeg structs in Godot/C# and not a subprocess. FFmpeg
`n8.1.2-29-g703dcc25b9` is pinned by immutable release URL and SHA-256 in each target manifest under
`native/age_movie_ffmpeg/`; changing either pin requires rerunning the full installed-movie gate. The shim
`n8.1.2-44-g7c533d0f86` is pinned by dated release URL, exact byte size, and SHA-256 in each target manifest under
`native/age_movie_ffmpeg/`. BtbN prunes older dated autobuild releases, so upstream availability is not permanent:
the current paired pin restores hosted builds, while a durable project-owned mirror remains necessary to prevent
future 404-driven repins. Changing either pin requires rerunning the full installed-movie gate. The shim
dynamically links an LGPL build made without GPL or nonfree components and uses
`libavformat`, `libavcodec`, `libavutil`, `libswscale`, and `libswresample`. Release artifacts must carry
the matching FFmpeg source/configuration and notices required by FFmpeg's

View File

@@ -26,7 +26,7 @@ whenever a tool's inputs/outputs change.**
| Tool | Purpose | Run | Reads → Writes |
|---|---|---|---|
| `validate.py` | Layered project validation front door. `core` regenerates/runtime-checks opcode metadata, lints canonical registries, runs pure Python tooling tests and the 502 .NET cases without the `Workspace` trait, checks generated opcode references, and runs `git diff --check`. `workspace` adds the 88 explicitly traited installed-data/native-oracle cases, corpus-derived global generation, real-data Python suites, full SYS4 decode, and Python RECOVER. `runtime` adds the Godot C# build and forced-portable threaded self-test. `full` combines all phases and adds the booted faithful-wait C# scene sweep. Selected prerequisites are strict: an unavailable game/corpus/Godot requirement fails before execution instead of becoming a green skip. Each gate has a timeout and UTF-8 log under `build/validation/validate-<timestamp>/`; Godot receives an isolated validation-owned user-data/log root there so it cannot read or modify the developer's saves/settings. The final table reports results/durations and a before/after Godot-process leak audit. | `validate.py` (defaults to `--level full`) · `--level core|workspace|runtime|full` · `--godot <console>` · `--game-root <install>` · `--verbose` · `--fail-fast` | sources + selected toolchain/game/corpus prerequisites → console summary + ⚙ `build/validation/validate-*/<gate>.log` |
| `validate.py` | Layered project validation front door. `core` regenerates/runtime-checks opcode metadata, lints canonical registries, runs pure Python tooling tests and the source-only .NET cases without the `Workspace` trait, checks generated opcode references, and runs `git diff --check`. Its .NET solution restore, CLI build, and test-project execution are separate low-memory gates; restore/build parallelism, compiler/MSBuild servers, server GC, and debug-symbol emission are disabled so constrained hosted runners do not kill Roslyn with exit 137. `workspace` adds the explicitly traited installed-data/native-oracle cases, corpus-derived global generation, real-data Python suites, full SYS4 decode, and Python RECOVER. `runtime` adds the Godot C# build and forced-portable threaded self-test. `full` combines all phases and adds the booted faithful-wait C# scene sweep. Selected prerequisites are strict: an unavailable game/corpus/Godot requirement fails before execution instead of becoming a green skip. Each gate has a timeout and UTF-8 log under `build/validation/validate-<timestamp>/`; Godot receives an isolated validation-owned user-data/log root there so it cannot read or modify the developer's saves/settings. The final table reports results/durations and a before/after Godot-process leak audit. | `validate.py` (defaults to `--level full`) · `--level core|workspace|runtime|full` · `--godot <console>` · `--game-root <install>` · `--verbose` · `--fail-fast` | sources + selected toolchain/game/corpus prerequisites → console summary + ⚙ `build/validation/validate-*/<gate>.log` |
| `test_validate.py` | Pure tests for launcher-equivalent explicit/environment/PATH/conventional resolution precedence, invalid-explicit hard failure, level composition, and final gate ordering. | `test_validate.py` | temporary files only |
Levels are cumulative around `core`: `workspace` means core+workspace-corpus, `runtime` means core+Godot,
@@ -45,7 +45,8 @@ access; failure logs are retained for seven days. The private remote's default a
`develop`; pushes and pull requests targeting it select the gate. The rewritten repository is published there,
and the first actual Linux/Gitea core run succeeded on 2026-08-03 before the later source-history sanitation;
its tree-equivalent rewritten commit is `524ea74`. The hosted gate also succeeded on the sanitized lineage at
`d673652` on 2026-08-03.
`d673652` on 2026-08-03. The same driver now owns the constrained-memory .NET environment rather than relying on
workflow-only settings, so local and hosted core/workspace runs share the Roslyn memory contract.
The artifact wrapper is `.gitea/workflows/linux-release-build.yml`. It runs independently from the fast core
gate on `develop` pushes, manual dispatch, and `v*` tag pushes. Independent Linux and Windows jobs use the same
@@ -290,18 +291,22 @@ send either the `step-limit` console block or the generated JSON.
## Native FFmpeg movie shim (Windows and Linux x64)
The target-specific dependency manifests pin immutable LGPL shared FFmpeg archives and SHA-256 hashes. Windows
development can use PowerShell/MSVC. Linux-hosted builds use Bash with Python 3, curl, MinGW-w64/binutils for the
Windows target, a native C compiler/binutils for Linux, and the ordinary archive/core utilities available.
The target-specific dependency manifests pin dated LGPL shared FFmpeg archives by exact byte size and SHA-256.
BtbN prunes older dated autobuild releases, so the bytes are immutable while retained but their upstream URLs
are not permanent; a failed 404 requires a paired manifest repin and full native/movie validation, while a
project-owned durable mirror remains the long-term fix. Bootstrap downloads remove partial files on HTTP failure
before validating the complete archive. Windows development can use PowerShell/MSVC. Linux-hosted builds use Bash
with Python 3, curl, MinGW-w64/binutils for the Windows target, a native C compiler/binutils for Linux, and the
ordinary archive/core utilities available.
| Tool | Purpose | Run | Reads → Writes |
|---|---|---|---|
| `native/age_movie_ffmpeg/bootstrap-win64.ps1` | Download, hash-check, extract, and version-check the pinned FFmpeg SDK. Returns the resolved SDK root. | `.\\native\\age_movie_ffmpeg\\bootstrap-win64.ps1 [-Destination <dir>]` | `dependency-win64.json`, network/archive cache → disposable `build/downloads/`, `build/ffmpeg-sdk/` |
| `native/age_movie_ffmpeg/bootstrap-win64.ps1` | Download, size/hash-check, extract, and version-check the pinned FFmpeg SDK. Returns the resolved SDK root. | `.\\native\\age_movie_ffmpeg\\bootstrap-win64.ps1 [-Destination <dir>]` | `dependency-win64.json`, network/archive cache → disposable `build/downloads/`, `build/ffmpeg-sdk/` |
| `native/age_movie_ffmpeg/build-win64.ps1` | Discover the MSVC x64 toolchain, build `age_movie_ffmpeg.dll`, and stage its exact shared-library/license dependencies. | `.\\native\\age_movie_ffmpeg\\build-win64.ps1 -SdkRoot <bootstrap-output> [-OutputDirectory <dir>]` | C ABI source + FFmpeg SDK → disposable `build/native/win-x64/` by default |
| `native/age_movie_ffmpeg/bootstrap-win64.sh` | Download, SHA-256-check, and extract the exact pinned Windows FFmpeg SDK, including its MinGW import libraries. Prints the resolved SDK root. | `native/age_movie_ffmpeg/bootstrap-win64.sh [destination]` | `dependency-win64.json`, network/archive cache → disposable `build/downloads/`, `build/ffmpeg-sdk/` |
| `native/age_movie_ffmpeg/bootstrap-win64.sh` | Download, size/SHA-256-check, and extract the exact pinned Windows FFmpeg SDK, including its MinGW import libraries. Prints the resolved SDK root. | `native/age_movie_ffmpeg/bootstrap-win64.sh [destination]` | `dependency-win64.json`, network/archive cache → disposable `build/downloads/`, `build/ffmpeg-sdk/` |
| `native/age_movie_ffmpeg/build-win64.sh` | Cross-build the AMD64 PE shim with MinGW, stage exactly five FFmpeg DLLs and the license, and run the static native-bundle contract gate. `MINGW_CC` and `MINGW_OBJDUMP` may override the standard tool names. | `sdk_root="$(native/age_movie_ffmpeg/bootstrap-win64.sh)"` then `native/age_movie_ffmpeg/build-win64.sh "$sdk_root" [output-directory]` | C ABI source + Windows FFmpeg SDK → disposable `build/native/win-x64/` by default, including `verification.json` |
| `tools/verify_windows_native.py` | Without executing Windows code, require the exact native bundle, AMD64 PE architecture, all seven ABI exports and five FFmpeg imports, and no Cygwin/MSYS compatibility runtime. Optionally writes the machine-readable verification report used by later packaging. | `python3 -X utf8 tools/verify_windows_native.py <bundle> [--objdump <MinGW-objdump>] [--report <json>]` | disposable Windows native bundle → stdout and optional JSON report |
| `native/age_movie_ffmpeg/bootstrap-linux-x64.sh` | Download, SHA-256-check, extract, and version-check the pinned Linux x64 FFmpeg SDK. Prints the resolved SDK root. | `native/age_movie_ffmpeg/bootstrap-linux-x64.sh [destination]` | `dependency-linux-x64.json`, network/archive cache → disposable `build/downloads/`, `build/ffmpeg-sdk/` |
| `native/age_movie_ffmpeg/bootstrap-linux-x64.sh` | Download, size/SHA-256-check, extract, and version-check the pinned Linux x64 FFmpeg SDK. Prints the resolved SDK root. | `native/age_movie_ffmpeg/bootstrap-linux-x64.sh [destination]` | `dependency-linux-x64.json`, network/archive cache → disposable `build/downloads/`, `build/ffmpeg-sdk/` |
| `native/age_movie_ffmpeg/build-linux-x64.sh` | Build the ELF64 x86-64 shim; stage the five exact FFmpeg SONAME libraries and license; reject stale `.so` files, unresolved/nonlocal FFmpeg dependencies, a missing `$ORIGIN` runpath, or a glibc requirement newer than the pinned 2.28 baseline. | `sdk_root="$(native/age_movie_ffmpeg/bootstrap-linux-x64.sh)"` then `native/age_movie_ffmpeg/build-linux-x64.sh "$sdk_root" [output-directory]` | C ABI source + FFmpeg SDK → disposable `build/native/linux-x64/` by default |
| `tools/movie-corpus-gate` | Discover every MPEG program stream stored under an `.AGF` catalog entry; decode every video frame and, when present, every audio block through the unpaced FFmpeg session; validate independent sequence dimensions, metadata, RGBA size, stereo finite PCM, monotonic video/audio timestamps, EOF, timeout, and teardown; then emit a per-asset JSON report. Audio fields include sample rate/channels, block and PCM-frame counts, first/last PTS, signal presence, and decode time. Exit 0 means the expected corpus count and every asset passed; exit 1 is a gate failure; exit 2 means the native shim is absent. | `dotnet run --project tools/movie-corpus-gate -- --output build/movie-corpus-ffmpeg.json --expected-count 213 --max-item-ms 30000` · optional `--native-dir <dir>` | `SYS4INI.BIN` + loose/ALF VFS assets + staged FFmpeg shim → stdout progress + disposable `build/movie-corpus-ffmpeg.json` |

View File

@@ -11,7 +11,7 @@ manifest_value() {
"$manifest" "$1"
}
for command in python3 curl sha256sum tar awk; do
for command in python3 curl sha256sum tar awk wc; do
command -v "$command" >/dev/null 2>&1 || {
echo "required command was not found: $command" >&2
exit 1
@@ -21,6 +21,7 @@ done
archive="$(manifest_value archive)"
url="$(manifest_value url)"
expected_hash="$(manifest_value sha256)"
expected_size="$(manifest_value size)"
expected_version="$(manifest_value ffmpeg_version)"
archive_root="${archive%.tar.xz}"
download_dir="$repo_root/build/downloads"
@@ -29,9 +30,14 @@ sdk_root="$destination/$archive_root"
mkdir -p -- "$download_dir" "$destination"
if [[ ! -f "$archive_path" ]]; then
curl --fail --location --retry 3 --output "$archive_path" "$url"
curl --fail --location --retry 3 --remove-on-error --output "$archive_path" "$url"
fi
actual_size="$(wc -c < "$archive_path")"
if [[ "$actual_size" != "$expected_size" ]]; then
echo "FFmpeg archive size mismatch: expected $expected_size, got $actual_size" >&2
exit 1
fi
actual_hash="$(sha256sum "$archive_path" | awk '{ print $1 }')"
if [[ "$actual_hash" != "$expected_hash" ]]; then
echo "FFmpeg archive SHA-256 mismatch: expected $expected_hash, got $actual_hash" >&2

View File

@@ -10,11 +10,24 @@ if ([string]::IsNullOrWhiteSpace($Destination)) {
$manifest = Get-Content -LiteralPath (Join-Path $PSScriptRoot 'dependency-win64.json') -Raw | ConvertFrom-Json
$downloadDir = Join-Path $repoRoot 'build\downloads'
$archivePath = Join-Path $downloadDir $manifest.archive
$partialArchivePath = "$archivePath.part"
$extractRoot = Join-Path $Destination ([IO.Path]::GetFileNameWithoutExtension($manifest.archive))
New-Item -ItemType Directory -Force -Path $downloadDir | Out-Null
if (-not (Test-Path -LiteralPath $archivePath)) {
Invoke-WebRequest -Uri $manifest.url -OutFile $archivePath
try {
Invoke-WebRequest -Uri $manifest.url -OutFile $partialArchivePath
Move-Item -LiteralPath $partialArchivePath -Destination $archivePath
}
finally {
if (Test-Path -LiteralPath $partialArchivePath) {
Remove-Item -LiteralPath $partialArchivePath -Force
}
}
}
$actualSize = (Get-Item -LiteralPath $archivePath).Length
if ($actualSize -ne $manifest.size) {
throw "FFmpeg archive size mismatch: expected $($manifest.size), got $actualSize"
}
$actualHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $archivePath).Hash.ToLowerInvariant()
if ($actualHash -ne $manifest.sha256) {
@@ -28,7 +41,7 @@ if (-not (Test-Path -LiteralPath (Join-Path $sdkRoot 'include\libavformat\avform
throw "Pinned FFmpeg SDK was not found at $sdkRoot"
}
$reported = & (Join-Path $sdkRoot 'bin\ffmpeg.exe') -version | Select-Object -First 1
$expectedVersion = $manifest.ffmpeg_version -replace '-20260721$', ''
$expectedVersion = $manifest.ffmpeg_version -replace '-\d{8}$', ''
if ($reported -notlike "*$expectedVersion*" ) {
throw "Unexpected FFmpeg build: $reported"
}

View File

@@ -11,7 +11,7 @@ manifest_value() {
"$manifest" "$1"
}
for command in python3 curl sha256sum awk; do
for command in python3 curl sha256sum awk wc; do
command -v "$command" >/dev/null 2>&1 || {
echo "required command was not found: $command" >&2
exit 1
@@ -21,6 +21,7 @@ done
archive="$(manifest_value archive)"
url="$(manifest_value url)"
expected_hash="$(manifest_value sha256)"
expected_size="$(manifest_value size)"
archive_root="${archive%.zip}"
download_directory="$repo_root/build/downloads"
archive_path="$download_directory/$archive"
@@ -28,9 +29,14 @@ sdk_root="$destination/$archive_root"
mkdir -p -- "$download_directory" "$destination"
if [[ ! -f "$archive_path" ]]; then
curl --fail --location --retry 3 --output "$archive_path" "$url"
curl --fail --location --retry 3 --remove-on-error --output "$archive_path" "$url"
fi
actual_size="$(wc -c < "$archive_path")"
if [[ "$actual_size" != "$expected_size" ]]; then
echo "FFmpeg archive size mismatch: expected $expected_size, got $actual_size" >&2
exit 1
fi
actual_hash="$(sha256sum "$archive_path" | awk '{ print $1 }')"
if [[ "$actual_hash" != "$expected_hash" ]]; then
echo "FFmpeg archive SHA-256 mismatch: expected $expected_hash, got $actual_hash" >&2

View File

@@ -1,11 +1,12 @@
{
"provider": "BtbN/FFmpeg-Builds",
"release_tag": "autobuild-2026-07-21-13-38",
"archive": "ffmpeg-n8.1.2-29-g703dcc25b9-linux64-lgpl-shared-8.1.tar.xz",
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-07-21-13-38/ffmpeg-n8.1.2-29-g703dcc25b9-linux64-lgpl-shared-8.1.tar.xz",
"sha256": "d0026954f10d303d1fc6517ed6b2290c42323b3958f11baafb1b330dfc564b36",
"ffmpeg_version": "n8.1.2-29-g703dcc25b9-20260721",
"ffmpeg_commit": "703dcc25b9",
"release_tag": "autobuild-2026-08-17-13-05",
"archive": "ffmpeg-n8.1.2-44-g7c533d0f86-linux64-lgpl-shared-8.1.tar.xz",
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-08-17-13-05/ffmpeg-n8.1.2-44-g7c533d0f86-linux64-lgpl-shared-8.1.tar.xz",
"size": 56931952,
"sha256": "194dc8d525ac8cea5a5ff2e6fd44754747e69af5a766e7a6727cce363bd65de6",
"ffmpeg_version": "n8.1.2-44-g7c533d0f86-20260817",
"ffmpeg_commit": "7c533d0f86",
"variant": "linux64 LGPL shared 8.1",
"minimum_glibc": "2.28",
"minimum_linux_kernel": "4.18"

View File

@@ -1,10 +1,11 @@
{
"provider": "BtbN/FFmpeg-Builds",
"release_tag": "autobuild-2026-07-21-13-38",
"archive": "ffmpeg-n8.1.2-29-g703dcc25b9-win64-lgpl-shared-8.1.zip",
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-07-21-13-38/ffmpeg-n8.1.2-29-g703dcc25b9-win64-lgpl-shared-8.1.zip",
"sha256": "50764b52d38cb0baf8af938c0e4ca886d2c6753b520b2c319b532ed5c17e7cbf",
"ffmpeg_version": "n8.1.2-29-g703dcc25b9-20260721",
"ffmpeg_commit": "703dcc25b9",
"release_tag": "autobuild-2026-08-17-13-05",
"archive": "ffmpeg-n8.1.2-44-g7c533d0f86-win64-lgpl-shared-8.1.zip",
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-08-17-13-05/ffmpeg-n8.1.2-44-g7c533d0f86-win64-lgpl-shared-8.1.zip",
"size": 70837934,
"sha256": "681b9ca6d8f9be1e01d8873ad16f8a632f8a22b9653f1044837de6d5979b0fd6",
"ffmpeg_version": "n8.1.2-44-g7c533d0f86-20260817",
"ffmpeg_commit": "7c533d0f86",
"variant": "win64 LGPL shared 8.1"
}

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env python3
from __future__ import annotations
import json
import re
import unittest
from pathlib import Path
@@ -15,6 +16,10 @@ MANAGED_SOLUTION = REPO / "godot/OME.sln"
LINUX_BUILD = REPO / "tools/build-linux-x64.sh"
WINDOWS_BUILD = REPO / "tools/build-windows-x64.sh"
WINDOWS_HOSTED_EXPORT = REPO / "tools/export-linux-x64.ps1"
LINUX_FFMPEG_MANIFEST = REPO / "native/age_movie_ffmpeg/dependency-linux-x64.json"
WINDOWS_FFMPEG_MANIFEST = REPO / "native/age_movie_ffmpeg/dependency-win64.json"
LINUX_FFMPEG_BOOTSTRAP = REPO / "native/age_movie_ffmpeg/bootstrap-linux-x64.sh"
WINDOWS_FFMPEG_BOOTSTRAP = REPO / "native/age_movie_ffmpeg/bootstrap-win64.sh"
def job(text: str, name: str, next_name: str | None) -> str:
@@ -38,6 +43,25 @@ class ReleaseWorkflowTests(unittest.TestCase):
cls.windows_build = WINDOWS_BUILD.read_text(encoding="utf-8")
cls.windows_hosted_export = WINDOWS_HOSTED_EXPORT.read_text(encoding="utf-8")
def test_ffmpeg_inputs_are_dated_size_and_hash_pinned(self) -> None:
manifests = [
json.loads(LINUX_FFMPEG_MANIFEST.read_text(encoding="utf-8")),
json.loads(WINDOWS_FFMPEG_MANIFEST.read_text(encoding="utf-8")),
]
self.assertEqual(1, len({manifest["release_tag"] for manifest in manifests}))
for manifest in manifests:
self.assertRegex(manifest["release_tag"], r"^autobuild-\d{4}-\d{2}-\d{2}-\d{2}-\d{2}$")
self.assertNotEqual("latest", manifest["release_tag"])
self.assertIn(f"/{manifest['release_tag']}/", manifest["url"])
self.assertTrue(manifest["url"].endswith("/" + manifest["archive"]))
self.assertIn(manifest["ffmpeg_commit"], manifest["archive"])
self.assertGreater(manifest["size"], 50_000_000)
self.assertRegex(manifest["sha256"], r"^[0-9a-f]{64}$")
for bootstrap in (LINUX_FFMPEG_BOOTSTRAP, WINDOWS_FFMPEG_BOOTSTRAP):
text = bootstrap.read_text(encoding="utf-8")
self.assertIn("manifest_value size", text)
self.assertIn("--remove-on-error", text)
def test_public_build_outputs_use_ome_branding(self) -> None:
self.assertIn('export_path="../build/export/linux-x64/OME"', self.export_presets)
self.assertIn('export_path="../build/export/windows-x64/OME.exe"', self.export_presets)
@@ -67,6 +91,15 @@ class ReleaseWorkflowTests(unittest.TestCase):
):
self.assertNotIn(legacy_name, active_surfaces)
def test_godot_csharp_uid_sidecars_match_sources(self) -> None:
godot_directory = REPO / "godot"
sources = {path.name for path in godot_directory.glob("*.cs")}
sidecar_sources = {
path.name.removesuffix(".uid")
for path in godot_directory.glob("*.cs.uid")
}
self.assertEqual(sources, sidecar_sources)
def test_build_jobs_are_linux_hosted_read_only_and_target_separate(self) -> None:
self.assertRegex(self.text, r"(?m)^permissions:\n contents: read$")
self.assertIn("runs-on: ubuntu-latest", self.linux)

View File

@@ -70,6 +70,8 @@ class EnvironmentResolutionTests(unittest.TestCase):
class GatePlanTests(unittest.TestCase):
def test_core_contains_no_workspace_or_runtime_gates(self) -> None:
keys = {gate.key for gate in validate.build_gate_plan("core")}
self.assertIn("engine-restore", keys)
self.assertIn("engine-cli-build", keys)
self.assertIn("engine-tests", keys)
self.assertIn("python-test_validate", keys)
self.assertNotIn("sys4-corpus-validate", keys)
@@ -77,6 +79,26 @@ class GatePlanTests(unittest.TestCase):
self.assertNotIn("age-cli-sweep", keys)
engine = next(gate for gate in validate.build_gate_plan("core") if gate.key == "engine-tests")
self.assertIn("Category!=Workspace", engine.command)
self.assertIn("--no-restore", engine.command)
self.assertIn("-m:1", engine.command)
self.assertIn("-p:BuildInParallel=false", engine.command)
self.assertEqual(validate.LOW_MEMORY_DOTNET_ENVIRONMENT, engine.environment)
self.assertIn(
"engine/Age.Engine.Tests/Age.Engine.Tests.csproj",
engine.command,
)
cli = next(
gate for gate in validate.build_gate_plan("core") if gate.key == "engine-cli-build"
)
self.assertIn("engine/Age.Cli/Age.Cli.csproj", cli.command)
self.assertIn("--no-restore", cli.command)
self.assertIn("-m:1", cli.command)
self.assertEqual(validate.LOW_MEMORY_DOTNET_ENVIRONMENT, cli.environment)
restore = next(
gate for gate in validate.build_gate_plan("core") if gate.key == "engine-restore"
)
self.assertIn("--disable-parallel", restore.command)
self.assertEqual(validate.LOW_MEMORY_DOTNET_ENVIRONMENT, restore.environment)
def test_workspace_extends_core(self) -> None:
core = {gate.key for gate in validate.build_gate_plan("core")}
@@ -90,6 +112,9 @@ class GatePlanTests(unittest.TestCase):
if gate.key == "engine-workspace-tests"
)
self.assertIn("Category=Workspace", installed.command)
self.assertIn("--no-restore", installed.command)
self.assertIn("-m:1", installed.command)
self.assertEqual(validate.LOW_MEMORY_DOTNET_ENVIRONMENT, installed.environment)
def test_runtime_requires_resolved_paths(self) -> None:
with self.assertRaisesRegex(ValueError, "resolved Godot"):

View File

@@ -55,6 +55,12 @@ WORKSPACE_GENERATED_INPUTS = (
paths.BUILD / "callscript-names.json",
paths.BUILD / "scjump-decisions.json",
)
LOW_MEMORY_DOTNET_ENVIRONMENT = (
("DOTNET_CLI_USE_MSBUILD_SERVER", "0"),
("MSBUILDDISABLENODEREUSE", "1"),
("DOTNET_gcServer", "0"),
("DOTNET_GCConserveMemory", "9"),
)
@dataclass(frozen=True)
@@ -156,15 +162,45 @@ def build_gate_plan(
)
for test in CORE_TESTS
)
gates.append(
Gate(
"engine-restore",
".NET engine restore",
(
"dotnet", "restore", "engine/AgeEngine.sln", "--nologo",
"--verbosity", "minimal", "--disable-parallel",
"-p:RestoreDisableParallel=true",
),
300,
LOW_MEMORY_DOTNET_ENVIRONMENT,
)
)
gates.append(
Gate(
"engine-cli-build",
".NET engine CLI build",
(
"dotnet", "build", "engine/Age.Cli/Age.Cli.csproj", "--no-restore", "--nologo",
"--verbosity", "minimal", "-m:1", "-p:UseSharedCompilation=false",
"-p:BuildInParallel=false", "-p:DebugType=None", "-p:DebugSymbols=false",
),
300,
LOW_MEMORY_DOTNET_ENVIRONMENT,
)
)
gates.append(
Gate(
"engine-tests",
".NET engine core tests",
(
"dotnet", "test", "engine/AgeEngine.sln", "--nologo", "--verbosity", "minimal",
"--filter", "Category!=Workspace", "-p:UseSharedCompilation=false",
"dotnet", "test", "engine/Age.Engine.Tests/Age.Engine.Tests.csproj",
"--no-restore", "--nologo",
"--verbosity", "minimal", "--filter", "Category!=Workspace", "-m:1",
"-p:UseSharedCompilation=false", "-p:BuildInParallel=false",
"-p:DebugType=None", "-p:DebugSymbols=false",
),
300,
LOW_MEMORY_DOTNET_ENVIRONMENT,
)
)
@@ -174,10 +210,14 @@ def build_gate_plan(
"engine-workspace-tests",
".NET installed-data and native-oracle tests",
(
"dotnet", "test", "engine/AgeEngine.sln", "--nologo", "--verbosity", "minimal",
"--filter", "Category=Workspace", "-p:UseSharedCompilation=false",
"dotnet", "test", "engine/Age.Engine.Tests/Age.Engine.Tests.csproj",
"--no-restore", "--nologo",
"--verbosity", "minimal", "--filter", "Category=Workspace", "-m:1",
"-p:UseSharedCompilation=false", "-p:BuildInParallel=false",
"-p:DebugType=None", "-p:DebugSymbols=false",
),
300,
LOW_MEMORY_DOTNET_ENVIRONMENT,
)
)
gates.append(