diff --git a/.gitea/workflows/package-hosts-verify.yml b/.gitea/workflows/package-hosts-verify.yml index 1ab27ca..ed17a6d 100644 --- a/.gitea/workflows/package-hosts-verify.yml +++ b/.gitea/workflows/package-hosts-verify.yml @@ -57,7 +57,6 @@ jobs: "$unity_bin" \ -batchmode \ -nographics \ - -quit \ -projectPath "$host" \ -runTests \ -testPlatform EditMode \ diff --git a/.gitea/workflows/published-upm-consumers-verify.yml b/.gitea/workflows/published-upm-consumers-verify.yml new file mode 100644 index 0000000..69bed6e --- /dev/null +++ b/.gitea/workflows/published-upm-consumers-verify.yml @@ -0,0 +1,37 @@ +name: Verify Published UPM Consumers + +on: + workflow_dispatch: + +jobs: + consumers: + runs-on: unity-2022.3.62f3 + container: + image: docker.1panel.live/unityci/editor:ubuntu-2022.3.62f3-windows-mono-3 + volumes: + - /www/dk_project/bt-recovery/gitea/runner/seedskey-unity-license:/root/.local/share/unity3d/Unity + - /www/dk_project/bt-recovery/gitea/runner/seedskey-unity-entitlements:/root/.config/unity3d/Unity/licenses + permissions: + contents: read + steps: + - name: Fetch exact Workspace revision + shell: bash + run: | + set -euo pipefail + ref="${{ gitea.sha }}" + git init . + git remote add origin "https://git.crash.work/ShrinkSDK/Workspace.git" + git fetch --depth=1 origin "$ref" + git checkout --detach FETCH_HEAD + + - name: Verify registry, Git tag, and installer consumers + shell: bash + run: | + set -euo pipefail + machine_id_file="/root/.local/share/unity3d/Unity/.machine-id" + if test -s "$machine_id_file"; then + cat "$machine_id_file" > /etc/machine-id + echo "Unity machine identity restored" + fi + git config --global url."https://ghfast.top/https://github.com/".insteadOf "https://github.com/" + bash Tools/UpmConsumerValidation/Validate-PublishedUpmConsumers.sh "$PWD" diff --git a/Assets/Editor/ShrinkSdkWorkspaceValidation.cs b/Assets/Editor/ShrinkSdkWorkspaceValidation.cs index 036744b..c2da17e 100644 --- a/Assets/Editor/ShrinkSdkWorkspaceValidation.cs +++ b/Assets/Editor/ShrinkSdkWorkspaceValidation.cs @@ -16,12 +16,12 @@ namespace ShrinkSDK.WorkspaceValidation private static readonly ExpectedPackage[] ExpectedPackages = { new ExpectedPackage("ShrinkApp.Core", "com.cneicy.shrink-app-core", "0.1.1"), - new ExpectedPackage("ShrinkApp.Starter.Basic", "com.cneicy.shrink-app-starter-basic", "0.1.0"), + new ExpectedPackage("ShrinkApp.Starter.Basic", "com.cneicy.shrink-app-starter-basic", "0.1.1"), new ExpectedPackage("ShrinkCommand", "com.cneicy.shrink-command", "0.2.0"), new ExpectedPackage("ShrinkCommand.Integration.App", "com.cneicy.shrink-command-integration-app", "0.1.0"), new ExpectedPackage("ShrinkCommand.Integration.EventBus", "com.cneicy.shrink-command-integration-eventbus", "0.1.1"), new ExpectedPackage("ShrinkCommand.Integration.Network", "com.cneicy.shrink-command-integration-network", "0.1.0"), - new ExpectedPackage("ShrinkContext.AppAdapter", "com.cneicy.shrink-context-app-adapter", "0.1.0"), + new ExpectedPackage("ShrinkContext.AppAdapter", "com.cneicy.shrink-context-app-adapter", "0.1.1"), new ExpectedPackage("ShrinkContext.Core", "com.cneicy.shrink-context-core", "0.1.0"), new ExpectedPackage("ShrinkContext.EventBusAdapter", "com.cneicy.shrink-context-eventbus-adapter", "0.1.0"), new ExpectedPackage("ShrinkDataSaver", "com.cneicy.shrink-datasaver", "2.2.0"), @@ -29,7 +29,7 @@ namespace ShrinkSDK.WorkspaceValidation new ExpectedPackage("ShrinkDataSaver.Integration.EventBus", "com.cneicy.shrink-datasaver-integration-eventbus", "2.1.0"), new ExpectedPackage("ShrinkEventBus", "com.cneicy.shrink-eventbus", "2.0.0"), new ExpectedPackage("ShrinkEventBus.Entities", "com.cneicy.shrink-eventbus-entities", "0.1.0"), - new ExpectedPackage("ShrinkInstaller", "com.cneicy.shrink-installer", "0.1.3"), + new ExpectedPackage("ShrinkInstaller", "com.cneicy.shrink-installer", "0.1.4"), new ExpectedPackage("ShrinkModFramework", "com.cneicy.shrink-mod-framework", "0.2.1"), new ExpectedPackage("ShrinkNetwork", "com.cneicy.shrink-network", "0.2.0"), new ExpectedPackage("ShrinkNetwork.Integration.App", "com.cneicy.shrink-network-integration-app", "0.1.0"), diff --git a/Assets/Modules/ShrinkApp.Core b/Assets/Modules/ShrinkApp.Core index 0fe4661..0497fd6 160000 --- a/Assets/Modules/ShrinkApp.Core +++ b/Assets/Modules/ShrinkApp.Core @@ -1 +1 @@ -Subproject commit 0fe46612735c438b0bf069c4edfcca775b83ed61 +Subproject commit 0497fd60664f751eb7b380f5c3d6c116c76858aa diff --git a/Assets/Modules/ShrinkApp.Starter.Basic b/Assets/Modules/ShrinkApp.Starter.Basic index ec2af3a..12eb248 160000 --- a/Assets/Modules/ShrinkApp.Starter.Basic +++ b/Assets/Modules/ShrinkApp.Starter.Basic @@ -1 +1 @@ -Subproject commit ec2af3a82d7b22eef20e2e72719be3a369d4f1f8 +Subproject commit 12eb248d1725fe1b90938365a19e06d6d5b85311 diff --git a/Assets/Modules/ShrinkCommand b/Assets/Modules/ShrinkCommand index 22d7605..438cc27 160000 --- a/Assets/Modules/ShrinkCommand +++ b/Assets/Modules/ShrinkCommand @@ -1 +1 @@ -Subproject commit 22d7605c7603fad36bd57f9cba77bab465752c9a +Subproject commit 438cc27213cfb962d3816042c1623ad9e2b5d861 diff --git a/Assets/Modules/ShrinkCommand.Integration.App b/Assets/Modules/ShrinkCommand.Integration.App index 929eaf8..c6c2eb0 160000 --- a/Assets/Modules/ShrinkCommand.Integration.App +++ b/Assets/Modules/ShrinkCommand.Integration.App @@ -1 +1 @@ -Subproject commit 929eaf8968ccb209335c511db42bb4da9ef1dd62 +Subproject commit c6c2eb08bb2035ba26f4f588bc2ca2c07f5fa6a9 diff --git a/Assets/Modules/ShrinkCommand.Integration.EventBus b/Assets/Modules/ShrinkCommand.Integration.EventBus index 6ef5adb..b6a1270 160000 --- a/Assets/Modules/ShrinkCommand.Integration.EventBus +++ b/Assets/Modules/ShrinkCommand.Integration.EventBus @@ -1 +1 @@ -Subproject commit 6ef5adb9c78dae094ed2eb20a20116afd7e703ef +Subproject commit b6a1270dbb13058c4ada0124221a963ec1fd4e89 diff --git a/Assets/Modules/ShrinkCommand.Integration.Network b/Assets/Modules/ShrinkCommand.Integration.Network index 17013e8..1551439 160000 --- a/Assets/Modules/ShrinkCommand.Integration.Network +++ b/Assets/Modules/ShrinkCommand.Integration.Network @@ -1 +1 @@ -Subproject commit 17013e83a83e6f320324af190dddde90d6a5c677 +Subproject commit 155143930ef0336494c6355fa7a03322f7c14d97 diff --git a/Assets/Modules/ShrinkContext.AppAdapter b/Assets/Modules/ShrinkContext.AppAdapter index fedc20c..041194a 160000 --- a/Assets/Modules/ShrinkContext.AppAdapter +++ b/Assets/Modules/ShrinkContext.AppAdapter @@ -1 +1 @@ -Subproject commit fedc20c1b90b978e505b89938275be79d8f1e676 +Subproject commit 041194af20e474837ddb60ab71dd83696224d895 diff --git a/Assets/Modules/ShrinkContext.Core b/Assets/Modules/ShrinkContext.Core index 341976f..02a0ece 160000 --- a/Assets/Modules/ShrinkContext.Core +++ b/Assets/Modules/ShrinkContext.Core @@ -1 +1 @@ -Subproject commit 341976fac60fdc21137c5a061ed76679e4d17d0f +Subproject commit 02a0ece826630cda775c6a39b19485fba6152740 diff --git a/Assets/Modules/ShrinkContext.EventBusAdapter b/Assets/Modules/ShrinkContext.EventBusAdapter index 86c9dc6..4e5c14e 160000 --- a/Assets/Modules/ShrinkContext.EventBusAdapter +++ b/Assets/Modules/ShrinkContext.EventBusAdapter @@ -1 +1 @@ -Subproject commit 86c9dc644ebdc766f255d1435c2bde0dfa3f2d85 +Subproject commit 4e5c14ea289a7a743442cd2f84e7e05ee44c4d64 diff --git a/Assets/Modules/ShrinkDataSaver b/Assets/Modules/ShrinkDataSaver index 7cfa6bf..b111c5f 160000 --- a/Assets/Modules/ShrinkDataSaver +++ b/Assets/Modules/ShrinkDataSaver @@ -1 +1 @@ -Subproject commit 7cfa6bf8e3bffa416372aa49832c6365ffa70c26 +Subproject commit b111c5f4379b1afb3d99c861d1a69c0e148a2f62 diff --git a/Assets/Modules/ShrinkDataSaver.Integration.App b/Assets/Modules/ShrinkDataSaver.Integration.App index e04a15c..5e613f3 160000 --- a/Assets/Modules/ShrinkDataSaver.Integration.App +++ b/Assets/Modules/ShrinkDataSaver.Integration.App @@ -1 +1 @@ -Subproject commit e04a15c1811cae204d227c47608cafe81c0266da +Subproject commit 5e613f3c0ad634f67b4ee77715c4250f33d3e03d diff --git a/Assets/Modules/ShrinkDataSaver.Integration.EventBus b/Assets/Modules/ShrinkDataSaver.Integration.EventBus index df7a0d6..320397c 160000 --- a/Assets/Modules/ShrinkDataSaver.Integration.EventBus +++ b/Assets/Modules/ShrinkDataSaver.Integration.EventBus @@ -1 +1 @@ -Subproject commit df7a0d68fe0ad83610c442c6cee793e7ad0ba7a3 +Subproject commit 320397c092b20effa0163eb047ec0596cbd858a5 diff --git a/Assets/Modules/ShrinkEventBus b/Assets/Modules/ShrinkEventBus index 7d7c0de..cdd9dbd 160000 --- a/Assets/Modules/ShrinkEventBus +++ b/Assets/Modules/ShrinkEventBus @@ -1 +1 @@ -Subproject commit 7d7c0de90703798a4490ca12be67f3be50861c52 +Subproject commit cdd9dbdb7316d19af6c24647062a11d2792ec4aa diff --git a/Assets/Modules/ShrinkEventBus.Entities b/Assets/Modules/ShrinkEventBus.Entities index 6602769..9460e2f 160000 --- a/Assets/Modules/ShrinkEventBus.Entities +++ b/Assets/Modules/ShrinkEventBus.Entities @@ -1 +1 @@ -Subproject commit 6602769bfe56b6cfdfff0b66d5476a6c3a3a3a0d +Subproject commit 9460e2f8e1b7ea41d09e258e5a4920d293275a51 diff --git a/Assets/Modules/ShrinkInstaller b/Assets/Modules/ShrinkInstaller index ece3f07..2ef9ad8 160000 --- a/Assets/Modules/ShrinkInstaller +++ b/Assets/Modules/ShrinkInstaller @@ -1 +1 @@ -Subproject commit ece3f072dd3b3cac52788f33d4b40ae2103a3b14 +Subproject commit 2ef9ad827ba221a81ceee79b7aecb43d7739186f diff --git a/Assets/Modules/ShrinkModFramework b/Assets/Modules/ShrinkModFramework index e91db64..9544601 160000 --- a/Assets/Modules/ShrinkModFramework +++ b/Assets/Modules/ShrinkModFramework @@ -1 +1 @@ -Subproject commit e91db64d760601925f643252068f5c559c557e44 +Subproject commit 95446018c307c0ed650ce92bef4ccc03c11a2eab diff --git a/Assets/Modules/ShrinkNetwork b/Assets/Modules/ShrinkNetwork index 54cd4aa..da609ca 160000 --- a/Assets/Modules/ShrinkNetwork +++ b/Assets/Modules/ShrinkNetwork @@ -1 +1 @@ -Subproject commit 54cd4aab56052d9bd2df914521634e8121675e86 +Subproject commit da609cabb97d83c7f58f69c2668af45b1fd5bb34 diff --git a/Assets/Modules/ShrinkNetwork.Integration.App b/Assets/Modules/ShrinkNetwork.Integration.App index b5262d2..1b04415 160000 --- a/Assets/Modules/ShrinkNetwork.Integration.App +++ b/Assets/Modules/ShrinkNetwork.Integration.App @@ -1 +1 @@ -Subproject commit b5262d223a8b85c0d44ba29c3878d669ee3f8506 +Subproject commit 1b04415fd7484f03babedd1a7845b412eab4eba2 diff --git a/Assets/Modules/ShrinkNetwork.Integration.EventBus b/Assets/Modules/ShrinkNetwork.Integration.EventBus index df3519f..00f50c1 160000 --- a/Assets/Modules/ShrinkNetwork.Integration.EventBus +++ b/Assets/Modules/ShrinkNetwork.Integration.EventBus @@ -1 +1 @@ -Subproject commit df3519fa960cd2c6c2fa50b9751fde63c0c8ea4e +Subproject commit 00f50c1289769459f3b153782a27486ae1d119c2 diff --git a/Assets/Modules/ShrinkShared.CodeGen b/Assets/Modules/ShrinkShared.CodeGen index a6f9853..bfb463e 160000 --- a/Assets/Modules/ShrinkShared.CodeGen +++ b/Assets/Modules/ShrinkShared.CodeGen @@ -1 +1 @@ -Subproject commit a6f98534c3364978a02e6add7b10b76d880f4192 +Subproject commit bfb463e4bc0b71d9f1d229e0c23764eeace7bd3d diff --git a/Assets/Modules/ShrinkTutorial b/Assets/Modules/ShrinkTutorial index b589f2a..b2ce563 160000 --- a/Assets/Modules/ShrinkTutorial +++ b/Assets/Modules/ShrinkTutorial @@ -1 +1 @@ -Subproject commit b589f2a385d14b0c434f35dedad6d516d11af46b +Subproject commit b2ce5637a001ed14c48839e7b238542f0d42e3ce diff --git a/DESIGN.md b/DESIGN.md index b7fad7c..32c0445 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -93,8 +93,8 @@ ShrinkSDK Workspace/ | `com.cneicy.shrink-tutorial` | 0.1.0 | 数据驱动引导、遮罩、锚点、触发与持久化 | | `com.cneicy.shrink-context-core` | 0.1.0 | 可逆效应、coeffect、fiber、声明式 loader 与诊断 | | `com.cneicy.shrink-app-core` | 0.1.1 | App 设置、服务门面、ClassicHost 兼容面与宿主协议 | -| `com.cneicy.shrink-app-starter-basic` | 0.1.0 | 默认 Context 组合根、配置资产和示例入口 | -| `com.cneicy.shrink-context-app-adapter` | 0.1.0 | ContextLoader 宿主、Profile/JSON、诊断与基准 | +| `com.cneicy.shrink-app-starter-basic` | 0.1.1 | 默认 Context 组合根、配置资产和示例入口 | +| `com.cneicy.shrink-context-app-adapter` | 0.1.1 | ContextLoader 宿主、Profile/JSON、诊断与基准 | | `com.cneicy.shrink-context-eventbus-adapter` | 0.1.0 | EventBus 生成绑定的可逆 EffectAttach 包装 | | `com.cneicy.shrink-datasaver-integration-eventbus` | 2.1.0 | DataSaver 事件桥 | | `com.cneicy.shrink-datasaver-integration-app` | 0.1.0 | DataSaver App installer/原生 Context 组件 | @@ -104,7 +104,7 @@ ShrinkSDK Workspace/ | `com.cneicy.shrink-network-integration-eventbus` | 0.1.1 | 网络事件广播、裁决结果与 delta 去重 | | `com.cneicy.shrink-network-integration-app` | 0.1.0 | Network App installer/原生 Context 组件 | | `com.cneicy.shrink-shared-codegen` | 0.1.0 | App、Command、Network 共用的 Editor-only IL 后处理注册表生成器 | -| `com.cneicy.shrink-installer` | 0.1.3 | 安全合并公开 registry、显示诊断并固定版本安装 Starter 或选定模块的 Editor 引导包 | +| `com.cneicy.shrink-installer` | 0.1.4 | 安全合并公开 registry、显示诊断并固定版本安装 Starter 或选定模块的 Editor 引导包 | `ShrinkShared.CodeGen` 不反向引用业务 asmdef,只按程序集名与类型全名读取 Cecil 元数据,因此业务包可以依赖它而不形成包循环。 diff --git a/README.md b/README.md index b730a8b..2b41a44 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ git submodule update --init --recursive } ``` -然后按精确版本添加包,例如 `com.cneicy.shrink-app-starter-basic: 0.1.0`。Git 备用安装同样必须固定标签,例如: +然后按精确版本添加包,例如 `com.cneicy.shrink-app-starter-basic: 0.1.1`。Git 备用安装同样必须固定标签,例如: ```text https://git.crash.work/ShrinkSDK/ShrinkEventBus.git#v2.0.0 @@ -37,7 +37,7 @@ https://git.crash.work/ShrinkSDK/ShrinkEventBus.git#v2.0.0 也可先通过固定标签安装 Editor 引导包: ```text -https://git.crash.work/ShrinkSDK/Installer.git#v0.1.3 +https://git.crash.work/ShrinkSDK/Installer.git#v0.1.4 ``` 随后在 Unity 打开 `ShrinkSDK/Packages`。安装器只合并 `com.cneicy` registry,并将内置目录中的固定版本及其必要的固定 UniTask revision 写入 manifest;它不写认证信息,也不复制模板到 `Assets`。 diff --git a/Tools/RepositoryMigration/Initialize-ShrinkSdkPackageRepositories.ps1 b/Tools/RepositoryMigration/Initialize-ShrinkSdkPackageRepositories.ps1 index 4132b5a..41c570f 100644 --- a/Tools/RepositoryMigration/Initialize-ShrinkSdkPackageRepositories.ps1 +++ b/Tools/RepositoryMigration/Initialize-ShrinkSdkPackageRepositories.ps1 @@ -38,6 +38,26 @@ $PackageDirectories = @( 'ShrinkTutorial' ) +$DevelopmentHostOnlyDependencies = @{ + 'com.cneicy.shrink-command-integration-network' = [ordered]@{ + 'com.cneicy.shrink-command-integration-app' = '0.1.0' + 'com.cneicy.shrink-datasaver-integration-app' = '0.1.0' + 'com.cneicy.shrink-network-integration-app' = '0.1.0' + } + 'com.cneicy.shrink-context-app-adapter' = [ordered]@{ + 'com.cneicy.shrink-app-starter-basic' = '0.1.1' + 'com.cneicy.shrink-command' = '0.2.0' + 'com.cneicy.shrink-command-integration-app' = '0.1.0' + 'com.cneicy.shrink-datasaver-integration-app' = '0.1.0' + 'com.cneicy.shrink-network' = '0.2.0' + 'com.cneicy.shrink-network-integration-app' = '0.1.0' + } + 'com.cneicy.shrink-eventbus-entities' = [ordered]@{ + 'com.unity.modules.physics' = '1.0.0' + 'com.unity.modules.uielements' = '1.0.0' + } +} + function Set-JsonProperty { param( [Parameter(Mandatory)] [object]$Target, @@ -251,7 +271,6 @@ jobs: "$unity_bin" \ -batchmode \ -nographics \ - -quit \ -projectPath "$PWD/Development~/UnityProject" \ -runTests \ -testPlatform EditMode \ @@ -261,6 +280,25 @@ jobs: $verifyWorkflow = $verifyWorkflow.Replace('__REPOSITORY_NAME__', $RepositoryName) Write-Utf8File -Path (Join-Path $PackageRoot '.gitea/workflows/unity-verify.yml') -Content $verifyWorkflow + $package = Get-Content -LiteralPath (Join-Path $PackageRoot 'package.json') -Raw | ConvertFrom-Json + $dependencies = [ordered]@{ + 'com.unity.test-framework' = '1.1.33' + } + if ($package.dependencies) { + foreach ($dependency in $package.dependencies.PSObject.Properties) { + if ($dependency.Name -ne 'com.cysharp.unitask') { + $dependencies[$dependency.Name] = [string]$dependency.Value + } + } + } + $dependencies[$PackageName] = 'file:../../..' + if ($DevelopmentHostOnlyDependencies.ContainsKey($PackageName)) { + foreach ($dependency in $DevelopmentHostOnlyDependencies[$PackageName].GetEnumerator()) { + $dependencies[$dependency.Key] = $dependency.Value + } + } + $dependencies['com.cysharp.unitask'] = 'https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#7c0f199fe0d3fc528024488ccd671e6c7b27745b' + $manifest = [ordered]@{ scopedRegistries = @( [ordered]@{ @@ -269,11 +307,7 @@ jobs: scopes = @($RegistryScope) } ) - dependencies = [ordered]@{ - 'com.unity.test-framework' = '1.1.33' - 'com.cysharp.unitask' = 'https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#7c0f199fe0d3fc528024488ccd671e6c7b27745b' - $PackageName = 'file:../../..' - } + dependencies = $dependencies testables = @($PackageName) } $developmentRoot = Join-Path $PackageRoot 'Development~/UnityProject' diff --git a/Tools/UpmConsumerValidation/Validate-PublishedUpmConsumers.sh b/Tools/UpmConsumerValidation/Validate-PublishedUpmConsumers.sh new file mode 100644 index 0000000..95e1ccf --- /dev/null +++ b/Tools/UpmConsumerValidation/Validate-PublishedUpmConsumers.sh @@ -0,0 +1,326 @@ +#!/usr/bin/env bash +set -euo pipefail + +workspace_root="${1:-$PWD}" +workspace_root="$(cd "$workspace_root" && pwd)" +unity_bin="${UNITY_EDITOR_PATH:-$(command -v unity-editor || command -v unity || command -v Unity || true)}" +consumer_root="$workspace_root/Temp/PublishedUpmConsumerValidation" + +if [[ ! -f "$workspace_root/ProjectSettings/ProjectVersion.txt" ]]; then + echo "Workspace ProjectVersion.txt was not found: $workspace_root" >&2 + exit 1 +fi + +if [[ -z "$unity_bin" ]]; then + echo "Unity editor executable was not found. Set UNITY_EDITOR_PATH." >&2 + exit 1 +fi + +case "$consumer_root" in + "$workspace_root"/Temp/*) ;; + *) echo "Consumer project must stay under the workspace Temp directory." >&2; exit 1 ;; +esac + +write_validator() { + local project_root="$1" + cat > "$project_root/Assets/Editor/PublishedUpmConsumerValidator.cs" <<'EOF' +#if UNITY_EDITOR +#nullable enable + +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json.Linq; +using UnityEditor; +using UnityEditor.Compilation; +using UnityEditor.PackageManager; +using UnityEditor.PackageManager.Requests; +using UnityEngine; + +public static class PublishedUpmConsumerValidator +{ + private const string RegistryUrl = "https://git.crash.work/api/packages/ShrinkSDK/npm/"; + private const string UniTaskUrl = "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#7c0f199fe0d3fc528024488ccd671e6c7b27745b"; + private static ResolveRequest? _installerResolve; + + public static void VerifyRegistry() + { + Run(() => + { + VerifyPackage("com.cneicy.shrink-app-starter-basic", "0.1.1", "ShrinkApp.Starter.Basic.Runtime"); + RequireManifestValue("com.cneicy.shrink-app-starter-basic", "0.1.1"); + RequireManifestValue("com.cysharp.unitask", UniTaskUrl); + RequireRegistry("com.cneicy", RegistryUrl); + }); + } + + public static void VerifyGitTag() + { + Run(() => + { + VerifyPackage("com.cneicy.shrink-eventbus", "2.0.0", "ShrinkEventBus.Runtime"); + RequireManifestValue( + "com.cneicy.shrink-eventbus", + "https://git.crash.work/ShrinkSDK/ShrinkEventBus.git#v2.0.0"); + RequireManifestValue("com.cysharp.unitask", UniTaskUrl); + }); + } + + public static void ApplyInstaller() + { + try + { + VerifyPackage("com.cneicy.shrink-installer", "0.1.4", "ShrinkInstaller.Editor"); + RequireManifestValue( + "com.cneicy.shrink-installer", + "https://git.crash.work/ShrinkSDK/Installer.git#v0.1.4"); + + var catalog = FindType("ShrinkSDK.Installer.ShrinkSdkPackageCatalog"); + var starter = catalog.GetField("StarterBasic", BindingFlags.Static | BindingFlags.NonPublic) + ?.GetValue(null) ?? throw new InvalidOperationException("Installer StarterBasic catalog entry was not found."); + var manifestStore = FindType("ShrinkSDK.Installer.ShrinkSdkManifestStore"); + var install = manifestStore.GetMethod( + "EnsurePackageInstallation", + BindingFlags.Static | BindingFlags.NonPublic) + ?? throw new InvalidOperationException("Installer manifest installation method was not found."); + install.Invoke(null, new[] { starter }); + + RequireManifestValue("com.cneicy.shrink-app-starter-basic", "0.1.1"); + RequireManifestValue("com.cysharp.unitask", UniTaskUrl); + RequireRegistry("com.cneicy", RegistryUrl); + RequireRegistry("com.example", "https://registry.npmjs.org/"); + + _installerResolve = Client.Resolve(); + EditorApplication.update += CompleteInstallerResolve; + } + catch (Exception exception) + { + Fail(Unwrap(exception)); + } + } + + public static void VerifyInstallerResult() + { + Run(() => + { + VerifyPackage("com.cneicy.shrink-installer", "0.1.4", "ShrinkInstaller.Editor"); + VerifyPackage("com.cneicy.shrink-app-starter-basic", "0.1.1", "ShrinkApp.Starter.Basic.Runtime"); + RequireManifestValue("com.cneicy.shrink-app-starter-basic", "0.1.1"); + RequireManifestValue("com.cysharp.unitask", UniTaskUrl); + RequireRegistry("com.cneicy", RegistryUrl); + RequireRegistry("com.example", "https://registry.npmjs.org/"); + }); + } + + private static void CompleteInstallerResolve() + { + if (_installerResolve == null || !_installerResolve.IsCompleted) + { + return; + } + + EditorApplication.update -= CompleteInstallerResolve; + try + { + if (_installerResolve.Status != StatusCode.Success) + { + throw new InvalidOperationException( + "Installer-triggered package resolve failed: " + _installerResolve.Error.message); + } + + Succeed("Installer wrote and resolved Starter Basic."); + } + catch (Exception exception) + { + Fail(Unwrap(exception)); + } + } + + private static void Run(Action action) + { + try + { + action(); + Succeed("Published UPM consumer validation passed."); + } + catch (Exception exception) + { + Fail(Unwrap(exception)); + } + } + + private static void VerifyPackage(string packageName, string version, string assemblyName) + { + var package = PackageInfo.GetAllRegisteredPackages() + .FirstOrDefault(candidate => string.Equals(candidate.name, packageName, StringComparison.Ordinal)); + if (package == null) + { + throw new InvalidOperationException("Package was not resolved: " + packageName); + } + + if (!string.Equals(package.version, version, StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Package version mismatch for " + packageName + ": " + package.version + " != " + version); + } + + if (!CompilationPipeline.GetAssemblies().Any(assembly => + string.Equals(assembly.name, assemblyName, StringComparison.Ordinal))) + { + throw new InvalidOperationException("Expected assembly was not compiled: " + assemblyName); + } + } + + private static void RequireManifestValue(string packageName, string expectedValue) + { + var manifest = ReadManifest(); + var actualValue = (string?)manifest["dependencies"]?[packageName]; + if (!string.Equals(actualValue, expectedValue, StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Manifest dependency mismatch for " + packageName + ": " + actualValue + " != " + expectedValue); + } + } + + private static void RequireRegistry(string scope, string url) + { + var registries = ReadManifest()["scopedRegistries"] as JArray; + var found = registries?.OfType().Any(registry => + string.Equals(NormalizeUrl((string?)registry["url"]), NormalizeUrl(url), StringComparison.OrdinalIgnoreCase) && + (registry["scopes"] as JArray)?.Values().Any(value => + string.Equals(value, scope, StringComparison.Ordinal)) == true) == true; + if (!found) + { + throw new InvalidOperationException("Scoped registry was not preserved or added: " + scope + " -> " + url); + } + } + + private static JObject ReadManifest() + { + var manifestPath = Path.Combine(Path.GetFullPath(Path.Combine(Application.dataPath, "..")), "Packages", "manifest.json"); + return JObject.Parse(File.ReadAllText(manifestPath)); + } + + private static Type FindType(string fullName) + { + return AppDomain.CurrentDomain.GetAssemblies() + .Select(assembly => assembly.GetType(fullName, false)) + .FirstOrDefault(type => type != null) + ?? throw new InvalidOperationException("Installer type was not loaded: " + fullName); + } + + private static string NormalizeUrl(string? url) => (url ?? string.Empty).Trim().TrimEnd('/') + "/"; + + private static Exception Unwrap(Exception exception) => + exception is TargetInvocationException { InnerException: not null } ? exception.InnerException : exception; + + private static void Succeed(string message) + { + Debug.Log(message); + EditorApplication.Exit(0); + } + + private static void Fail(Exception exception) + { + Debug.LogException(exception); + EditorApplication.Exit(1); + } +} +#endif +EOF +} + +prepare_consumer() { + local name="$1" + local project_root="$consumer_root/$name" + mkdir -p "$project_root/Packages" "$project_root/Assets/Editor" "$project_root/ProjectSettings" + cp "$workspace_root/ProjectSettings/ProjectVersion.txt" "$project_root/ProjectSettings/ProjectVersion.txt" + write_validator "$project_root" + printf '%s' "$project_root" +} + +write_manifest() { + local project_root="$1" + local manifest="$2" + printf '%s\n' "$manifest" > "$project_root/Packages/manifest.json" +} + +show_failure() { + local log_path="$1" + echo "Unity consumer validation failed. Relevant log lines:" >&2 + grep -in -E 'exception|buildfailed|build failed|error|failed|compilererror|invalidoperation|nullreference|package manager' "$log_path" | tail -n 180 >&2 || true +} + +run_unity() { + local project_root="$1" + local method="$2" + local log_path="$3" + local wait_for_resolve="$4" + local args=( + -batchmode + -nographics + -projectPath "$project_root" + -executeMethod "$method" + -logFile "$log_path" + ) + if [[ "$wait_for_resolve" != "true" ]]; then + args+=(-quit) + fi + + if ! "$unity_bin" "${args[@]}"; then + show_failure "$log_path" + exit 1 + fi +} + +rm -rf "$consumer_root" +mkdir -p "$consumer_root" + +registry_project="$(prepare_consumer registry)" +write_manifest "$registry_project" '{ + "scopedRegistries": [ + { + "name": "ShrinkSDK", + "url": "https://git.crash.work/api/packages/ShrinkSDK/npm/", + "scopes": ["com.cneicy"] + } + ], + "dependencies": { + "com.cneicy.shrink-app-starter-basic": "0.1.1", + "com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#7c0f199fe0d3fc528024488ccd671e6c7b27745b", + "com.unity.nuget.newtonsoft-json": "3.2.2" + } +}' +run_unity "$registry_project" PublishedUpmConsumerValidator.VerifyRegistry "$registry_project/registry.log" false + +git_project="$(prepare_consumer git-tag)" +write_manifest "$git_project" '{ + "dependencies": { + "com.cneicy.shrink-eventbus": "https://git.crash.work/ShrinkSDK/ShrinkEventBus.git#v2.0.0", + "com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#7c0f199fe0d3fc528024488ccd671e6c7b27745b", + "com.unity.nuget.newtonsoft-json": "3.2.2" + } +}' +run_unity "$git_project" PublishedUpmConsumerValidator.VerifyGitTag "$git_project/git-tag.log" false + +installer_project="$(prepare_consumer installer)" +write_manifest "$installer_project" '{ + "scopedRegistries": [ + { + "name": "Existing Registry", + "url": "https://registry.npmjs.org/", + "scopes": ["com.example"] + } + ], + "dependencies": { + "com.cneicy.shrink-installer": "https://git.crash.work/ShrinkSDK/Installer.git#v0.1.4", + "com.unity.nuget.newtonsoft-json": "3.2.2", + "com.unity.test-framework": "1.1.33" + } +}' +run_unity "$installer_project" PublishedUpmConsumerValidator.ApplyInstaller "$installer_project/installer-apply.log" true +run_unity "$installer_project" PublishedUpmConsumerValidator.VerifyInstallerResult "$installer_project/installer-result.log" false + +rm -rf "$consumer_root" +echo "Published UPM consumer validation passed: registry, exact Git tag, installer."