[CmdletBinding()] param( [Parameter(Mandatory)] [string]$StagingRoot, [string]$SourceRoot = (Resolve-Path (Join-Path $PSScriptRoot '../..')).Path ) $ErrorActionPreference = 'Stop' $RegistryUrl = 'https://git.crash.work/api/packages/ShrinkSDK/npm/' $RegistryScope = 'com.cneicy' $RepositoryBaseUrl = 'https://git.crash.work/ShrinkSDK' $UnityVersion = '2022.3.62f3' $UnityRevision = '96770f904ca7' $PackageDirectories = @( 'ShrinkApp.Core', 'ShrinkApp.Starter.Basic', 'ShrinkCommand', 'ShrinkCommand.Integration.App', 'ShrinkCommand.Integration.EventBus', 'ShrinkCommand.Integration.Network', 'ShrinkContext.AppAdapter', 'ShrinkContext.Core', 'ShrinkContext.EventBusAdapter', 'ShrinkDataSaver', 'ShrinkDataSaver.Integration.App', 'ShrinkDataSaver.Integration.EventBus', 'ShrinkEventBus', 'ShrinkEventBus.Entities', 'ShrinkInstaller', 'ShrinkModFramework', 'ShrinkNetwork', 'ShrinkNetwork.Integration.App', 'ShrinkNetwork.Integration.EventBus', 'ShrinkShared.CodeGen', 'ShrinkTutorial' ) $DevelopmentHostOnlyDependencies = @{ 'com.cneicy.shrink-command-integration-network' = [ordered]@{ 'com.cneicy.shrink-command-integration-app' = '0.1.1' 'com.cneicy.shrink-datasaver-integration-app' = '0.1.1' 'com.cneicy.shrink-network-integration-app' = '0.1.1' } 'com.cneicy.shrink-context-app-adapter' = [ordered]@{ 'com.cneicy.shrink-app-starter-basic' = '0.2.0' 'com.cneicy.shrink-command' = '0.2.0' 'com.cneicy.shrink-command-integration-app' = '0.1.1' 'com.cneicy.shrink-datasaver-integration-app' = '0.1.1' 'com.cneicy.shrink-network' = '0.2.1' 'com.cneicy.shrink-network-integration-app' = '0.1.1' } '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, [Parameter(Mandatory)] [string]$Name, [Parameter(Mandatory)] [object]$Value ) $property = $Target.PSObject.Properties[$Name] if ($null -eq $property) { $Target | Add-Member -MemberType NoteProperty -Name $Name -Value $Value return } $property.Value = $Value } function Write-Utf8File { param( [Parameter(Mandatory)] [string]$Path, [Parameter(Mandatory)] [AllowEmptyString()] [string]$Content ) $parent = Split-Path -Parent $Path New-Item -ItemType Directory -Path $parent -Force | Out-Null [System.IO.File]::WriteAllText($Path, $Content, [System.Text.UTF8Encoding]::new($false)) } function Update-PackageMetadata { param( [Parameter(Mandatory)] [string]$PackageRoot, [Parameter(Mandatory)] [string]$RepositoryName ) $packagePath = Join-Path $PackageRoot 'package.json' $package = Get-Content -LiteralPath $packagePath -Raw | ConvertFrom-Json Set-JsonProperty -Target $package -Name 'documentationUrl' -Value "$RepositoryBaseUrl/$RepositoryName" $changelogPath = Join-Path $PackageRoot 'CHANGELOG.md' if (Test-Path -LiteralPath $changelogPath) { Set-JsonProperty -Target $package -Name 'changelogUrl' -Value "$RepositoryBaseUrl/$RepositoryName/src/branch/main/CHANGELOG.md" } $licensePath = Join-Path $PackageRoot 'LICENSE' if (Test-Path -LiteralPath $licensePath) { Set-JsonProperty -Target $package -Name 'licensesUrl' -Value "$RepositoryBaseUrl/$RepositoryName/src/branch/main/LICENSE" } if ($null -eq $package.author) { $package | Add-Member -MemberType NoteProperty -Name 'author' -Value ([PSCustomObject]@{}) } Set-JsonProperty -Target $package.author -Name 'name' -Value 'cneicy' Set-JsonProperty -Target $package.author -Name 'url' -Value $RepositoryBaseUrl Write-Utf8File -Path $packagePath -Content (($package | ConvertTo-Json -Depth 16) + [Environment]::NewLine) Get-ChildItem -LiteralPath $PackageRoot -Recurse -File -Filter '*.md' | ForEach-Object { $content = Get-Content -LiteralPath $_.FullName -Raw $updated = $content.Replace('https://github.com/cneicy/', "$RepositoryBaseUrl/") if ($updated -ne $content) { Write-Utf8File -Path $_.FullName -Content $updated } } } function Write-PublishFiles { param( [Parameter(Mandatory)] [string]$PackageRoot, [Parameter(Mandatory)] [string]$PackageName, [Parameter(Mandatory)] [string]$RepositoryName ) $npmIgnore = @' .git/ .gitea/ Development~/ Tools~/ *.csproj *.sln *.user *.DotSettings.user '@ Write-Utf8File -Path (Join-Path $PackageRoot '.npmignore') -Content ($npmIgnore + [Environment]::NewLine) $repositoryGitIgnore = @' /Development~/UnityProject/[Ll]ibrary/ /Development~/UnityProject/[Tt]emp/ /Development~/UnityProject/[Oo]bj/ /Development~/UnityProject/[Ll]ogs/ /Development~/UnityProject/[Uu]ser[Ss]ettings/ /Development~/UnityProject/TestResults/ /Tools~/**/[Bb]in/ /Tools~/**/[Oo]bj/ *.user *.DotSettings.user '@ $repositoryGitIgnorePath = Join-Path $PackageRoot '.gitignore' if (Test-Path -LiteralPath $repositoryGitIgnorePath) { $repositoryGitIgnore = (Get-Content -LiteralPath $repositoryGitIgnorePath -Raw).TrimEnd() + [Environment]::NewLine + $repositoryGitIgnore } Write-Utf8File -Path $repositoryGitIgnorePath -Content ($repositoryGitIgnore + [Environment]::NewLine) $publishWorkflow = @' name: Publish UPM package on: push: tags: - 'v*' workflow_dispatch: jobs: publish: runs-on: ubuntu-latest permissions: contents: read packages: write env: NODE_AUTH_TOKEN: ${{ secrets.SHRINKSDK_PACKAGE_TOKEN }} steps: - name: Fetch exact tagged release archive env: GITEA_REF: ${{ gitea.ref }} shell: bash run: | set -eu tag="${GITEA_REF#refs/tags/}" case "$tag" in v[0-9]*) ;; *) echo "Expected a version tag ref, got: $GITEA_REF" >&2; exit 1 ;; esac export SHRINKSDK_ARCHIVE_URL="https://git.crash.work/ShrinkSDK/__REPOSITORY_NAME__/archive/${tag}.tar.gz" node --input-type=module <<'NODE' import { writeFile } from 'node:fs/promises'; const response = await fetch(process.env.SHRINKSDK_ARCHIVE_URL); if (!response.ok) { throw new Error(`Release archive download failed: ${response.status} ${response.statusText}`); } await writeFile('release.tar.gz', new Uint8Array(await response.arrayBuffer())); NODE mkdir release tar -xzf release.tar.gz --strip-components=1 -C release rm -f release.tar.gz printf '%s' "$tag" > release/.shrink-sdk-release-tag - name: Validate immutable release version shell: bash run: | set -eu cd release tag="$(cat .shrink-sdk-release-tag)" version="$(node -p "require('./package.json').version")" test "$tag" = "v$version" npm pack --dry-run - name: Publish to ShrinkSDK registry shell: bash run: | set -eu : "${NODE_AUTH_TOKEN:?SHRINKSDK_PACKAGE_TOKEN is required}" cd release npmrc="$HOME/.npmrc" cleanup() { rm -f "$npmrc"; } trap cleanup EXIT printf '%s\n' \ 'registry=https://git.crash.work/api/packages/ShrinkSDK/npm/' \ '//git.crash.work/api/packages/ShrinkSDK/npm/:_authToken=${NODE_AUTH_TOKEN}' > "$npmrc" npm publish --registry=https://git.crash.work/api/packages/ShrinkSDK/npm/ '@ $publishWorkflow = $publishWorkflow.Replace('__REPOSITORY_NAME__', $RepositoryName) Write-Utf8File -Path (Join-Path $PackageRoot '.gitea/workflows/publish.yml') -Content $publishWorkflow $verifyWorkflow = @' name: Verify standalone Unity package on: workflow_dispatch: jobs: editmode: 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 steps: - name: Fetch selected revision shell: bash run: | set -eu ref="${{ gitea.sha }}" git init . git remote add origin "https://git.crash.work/ShrinkSDK/__REPOSITORY_NAME__.git" git fetch --depth=1 origin "$ref" git checkout --detach FETCH_HEAD - name: Run package EditMode tests shell: bash run: | set -eu 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/" unity_bin="$(command -v unity-editor || command -v unity || command -v Unity || true)" test -n "$unity_bin" "$unity_bin" \ -batchmode \ -nographics \ -projectPath "$PWD/Development~/UnityProject" \ -runTests \ -testPlatform EditMode \ -testResults "$PWD/TestResults/editmode.xml" \ -logFile "$PWD/TestResults/unity.log" '@ $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]@{ name = 'ShrinkSDK' url = $RegistryUrl scopes = @($RegistryScope) } ) dependencies = $dependencies testables = @($PackageName) } $developmentRoot = Join-Path $PackageRoot 'Development~/UnityProject' Write-Utf8File -Path (Join-Path $developmentRoot 'Packages/manifest.json') -Content (($manifest | ConvertTo-Json -Depth 12) + [Environment]::NewLine) Write-Utf8File -Path (Join-Path $developmentRoot 'ProjectSettings/ProjectVersion.txt') -Content "m_EditorVersion: $UnityVersion`nm_EditorVersionWithRevision: $UnityVersion ($UnityRevision)`n" Write-Utf8File -Path (Join-Path $developmentRoot 'Assets/.gitkeep') -Content '' Write-Utf8File -Path (Join-Path $developmentRoot '.gitignore') -Content @' [Ll]ibrary/ [Tt]emp/ [Oo]bj/ [Ll]ogs/ [Uu]ser[Ss]ettings/ TestResults/ '@ } function Add-EventBusDotNetTools { param( [Parameter(Mandatory)] [string]$PackageRoot, [Parameter(Mandatory)] [string]$RepositorySourceRoot ) $source = Join-Path $RepositorySourceRoot 'DotNet' $destination = Join-Path $PackageRoot 'Tools~/DotNet' New-Item -ItemType Directory -Path (Split-Path -Parent $destination) -Force | Out-Null Copy-Item -LiteralPath $source -Destination $destination -Recurse -Force $coreProjectPath = Join-Path $destination 'ShrinkEventBus.Core/ShrinkEventBus.Core.csproj' $coreProject = Get-Content -LiteralPath $coreProjectPath -Raw $coreProject = $coreProject.Replace('..\..\Assets\Modules\ShrinkEventBus\Runtime\', '..\..\..\Runtime\') Write-Utf8File -Path $coreProjectPath -Content $coreProject $readmePath = Join-Path $destination 'README.md' $readme = Get-Content -LiteralPath $readmePath -Raw $readme = $readme.Replace('DotNet/', 'Tools~/DotNet/') Write-Utf8File -Path $readmePath -Content $readme } function Add-ModFrameworkFixtureBuilder { param( [Parameter(Mandatory)] [string]$PackageRoot, [Parameter(Mandatory)] [string]$RepositorySourceRoot ) $source = Join-Path $RepositorySourceRoot 'Tools/ShrinkModFixtureBuilder' $destination = Join-Path $PackageRoot 'Tools~/FixtureBuilder' New-Item -ItemType Directory -Path (Split-Path -Parent $destination) -Force | Out-Null Copy-Item -LiteralPath $source -Destination $destination -Recurse -Force $fixtureProject = @' netstandard2.1 9.0 enable false ExternalFixture.Mod ExternalFixture $(RuntimeAssemblyPath) false '@ Write-Utf8File -Path (Join-Path $destination 'ShrinkModFixtureBuilder.csproj') -Content $fixtureProject $rebuildScript = @' [CmdletBinding()] param( [string]$UnityProjectRoot ) $ErrorActionPreference = 'Stop' $packageRoot = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '../..')).Path if (-not $UnityProjectRoot) { $UnityProjectRoot = Join-Path $packageRoot 'Development~/UnityProject' } $resolvedUnityProjectRoot = (Resolve-Path -LiteralPath $UnityProjectRoot).Path $fixtureProject = Join-Path $PSScriptRoot 'ShrinkModFixtureBuilder.csproj' $fixtureOutputRoot = Join-Path $resolvedUnityProjectRoot 'Temp/ShrinkModFixtureBuilder' $fixtureTargetRoot = Join-Path $packageRoot 'Tests/Fixtures' $runtimeAssemblyPath = Join-Path $resolvedUnityProjectRoot 'Temp/Bin/Debug/ShrinkModFramework.Runtime/ShrinkModFramework.Runtime.dll' if (-not (Test-Path -LiteralPath $runtimeAssemblyPath)) { throw "ShrinkModFramework.Runtime.dll was not found. Compile the Unity development host first: $resolvedUnityProjectRoot" } foreach ($variant in 'V1', 'V2', 'V3') { $outputDirectory = Join-Path $fixtureOutputRoot $variant $intermediateDirectory = Join-Path $fixtureOutputRoot "obj/$variant/" dotnet build $fixtureProject /m:1 --nologo ` -p:FixtureVariant=$variant ` -p:RuntimeAssemblyPath=$runtimeAssemblyPath ` -p:BaseIntermediateOutputPath=$intermediateDirectory ` -p:OutputPath=$outputDirectory if ($LASTEXITCODE -ne 0) { throw "External fixture $variant build failed with exit code $LASTEXITCODE." } $source = Join-Path $outputDirectory 'ExternalFixture.Mod.dll' $targetName = switch ($variant) { 'V1' { 'ExternalFixture.Mod.V1.dll.bytes' } 'V2' { 'ExternalFixture.Mod.V2.Failing.dll.bytes' } 'V3' { 'ExternalFixture.Mod.V3.dll.bytes' } } Copy-Item -LiteralPath $source -Destination (Join-Path $fixtureTargetRoot $targetName) -Force } Write-Host 'ShrinkModFramework external fixture DLLs rebuilt.' '@ Write-Utf8File -Path (Join-Path $destination 'Rebuild-ShrinkModFixtures.ps1') -Content $rebuildScript } $resolvedSourceRoot = (Resolve-Path -LiteralPath $SourceRoot).Path if (Test-Path -LiteralPath $StagingRoot) { throw "StagingRoot already exists: $StagingRoot" } New-Item -ItemType Directory -Path $StagingRoot -Force | Out-Null $releaseMap = [System.Collections.Generic.List[object]]::new() foreach ($directory in $PackageDirectories) { $source = Join-Path $resolvedSourceRoot "Assets/Modules/$directory" if (-not (Test-Path -LiteralPath $source)) { throw "Package source was not found: $source" } $destination = Join-Path $StagingRoot $directory Copy-Item -LiteralPath $source -Destination $destination -Recurse -Force $repositoryName = if ($directory -eq 'ShrinkInstaller') { 'Installer' } else { $directory } Update-PackageMetadata -PackageRoot $destination -RepositoryName $repositoryName $package = Get-Content -LiteralPath (Join-Path $destination 'package.json') -Raw | ConvertFrom-Json Write-PublishFiles -PackageRoot $destination -PackageName $package.name -RepositoryName $repositoryName if ($directory -eq 'ShrinkEventBus') { Add-EventBusDotNetTools -PackageRoot $destination -RepositorySourceRoot $resolvedSourceRoot } if ($directory -eq 'ShrinkModFramework') { Add-ModFrameworkFixtureBuilder -PackageRoot $destination -RepositorySourceRoot $resolvedSourceRoot } $releaseMap.Add([PSCustomObject]@{ directory = $directory repositoryName = $repositoryName package = $package.name version = $package.version repository = "$RepositoryBaseUrl/$repositoryName.git" }) } Write-Utf8File -Path (Join-Path $StagingRoot 'package-map.json') -Content (($releaseMap | ConvertTo-Json -Depth 8) + [Environment]::NewLine) Write-Host "Prepared $($releaseMap.Count) package repositories in $StagingRoot"