Skip to content

Commit ccf5f16

Browse files
authored
[WIP] Signed updates (#47)
* initial manifest augmention with signatures * move to new projects * wire deployment process * support local deploy server * deploy a newer version, so updating can be tested * Update ModdingToolBase and manifest signing config Updated ModdingToolBase submodule. Refactored ManifestDownloadConfiguration to use ManifestDownloadConfiguration type and simplified its properties. Added ManifestSigningConfiguration with required ES256 signature policy. Added necessary using directive for security features. * Add trust cert verification to release workflow Add a PowerShell step in release.yml to verify that the embedded modverify-trust.cer exists, is a valid public X.509 certificate, and does not contain a private key. Fail the workflow with a clear error if any check fails. Also update the ModdingToolBase submodule to the latest commit. * Update cert handling and add LOCAL_DEPLOY support - Update ModdingToolBase submodule to latest commit - Add LOCAL_DEPLOY constant for local deployment builds - Embed modverify-trust.cer as a resource if present - Register trusted certs at runtime, supporting dev certs in DEBUG/LOCAL_DEPLOY - Refactor Program.cs to use embedded cert resource name constant * Add LocalDeploy flag and update ModdingToolBase submodule Added /p:LocalDeploy=true to dotnet build commands in deploy-local.ps1 for local deployment logic. Updated ModdingToolBase submodule to commit 0e97dc475c42a4ebf084e4917b526e3dbee50b47. * add plans and design for signed updates * Refactor release pipeline, update local deploy & channels Centralize release logic in Publish-Release.ps1, add dual-publish and compatibility-updater options, and update environment variables for flexibility. Rewrite deploy-local.ps1 to use a shared base script and Nbgv helpers. Update ModdingToolBase submodule. Switch .NET Framework update channel to /v2/ * update release * update app version * pin the current updater * update sub * fix certificates are not loaded on before resume updating * update submodule * fix possible exception in spinner * update sub * support multiple pinned certificates * support --noRestart option * add update rountrip integration tests * update solution entries * update sub * update sub * update sub * next try linux * remove doc * move documentation * update deps * reprare release * add root certificate * update action dep * remove linux build as that's covered with the .Net 10 release * udpate sub * pin main branch again
1 parent a3cb110 commit ccf5f16

29 files changed

Lines changed: 424 additions & 162 deletions
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: ModVerify Update Integration Test
2+
3+
on:
4+
workflow_call:
5+
workflow_dispatch:
6+
7+
jobs:
8+
update-cycle:
9+
name: Update cycle (${{ matrix.scenario.name }})
10+
runs-on: windows-latest
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
scenario:
15+
- { name: single, script: ./test-local-update.ps1 }
16+
- { name: dual, script: ./test-local-update-dual.ps1 }
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v6
20+
with:
21+
fetch-depth: 0
22+
submodules: recursive
23+
24+
- name: Setup .NET
25+
uses: actions/setup-dotnet@v5
26+
with:
27+
dotnet-version: 10.0.x
28+
29+
- name: Run ${{ matrix.scenario.name }}-channel update cycle
30+
shell: pwsh
31+
run: ${{ matrix.scenario.script }}
32+
33+
- name: Upload diagnostics on failure
34+
if: failure()
35+
uses: actions/upload-artifact@v7
36+
with:
37+
name: update-cycle-${{ matrix.scenario.name }}-logs
38+
# Updater log: %TEMP%\extUpdateLog-*.txt; ModVerify app log: %APPDATA%\ModVerify\*.txt
39+
path: |
40+
${{ runner.temp }}\extUpdateLog-*.txt
41+
${{ env.APPDATA }}\ModVerify\*.txt
42+
if-no-files-found: ignore
43+
retention-days: 7

.github/workflows/release.yml

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,38 @@ on:
1313

1414
env:
1515
TOOL_PROJ_PATH: ./src/ModVerify.CliApp/ModVerify.CliApp.csproj
16-
CREATOR_PROJ_PATH: ./modules/ModdingToolBase/src/AnakinApps/ApplicationManifestCreator/ApplicationManifestCreator.csproj
17-
UPLOADER_PROJ_PATH: ./modules/ModdingToolBase/src/AnakinApps/FtpUploader/FtpUploader.csproj
16+
PUBLISH_SCRIPT: ./modules/ModdingToolBase/scripts/Publish-Release.ps1
1817
TOOL_EXE: ModVerify.exe
1918
UPDATER_EXE: AnakinRaW.ExternalUpdater.exe
20-
MANIFEST_CREATOR: AnakinRaW.ApplicationManifestCreator.dll
21-
SFTP_UPLOADER: AnakinRaW.FtpUploader.dll
19+
EMBEDDED_TRUST_CERT: src/ModVerify.CliApp/Resources/Certs/AET-root.cer
2220
ORIGIN_BASE: https://republicatwar.com/downloads/ModVerify
23-
ORIGIN_BASE_PART: downloads/ModVerify/
21+
SFTP_BASE_PATH: downloads/ModVerify/
2422
BRANCH_NAME: ${{ github.event.inputs.branch || 'stable' }}
2523

24+
# Migration-release values. Leave empty for a normal release; populate to enable.
25+
#
26+
# Origin URL of the next-generation channel, written into the manifest's componentOriginInfo.
27+
NEXT_ORIGIN_BASE: https://republicatwar.com/downloads/ModVerify/v2
28+
29+
# SFTP path the next-generation channel uploads to. Set together with NEXT_ORIGIN_BASE.
30+
NEXT_SFTP_BASE_PATH: downloads/ModVerify/v2/
31+
32+
# Previously-deployed updater used in place of the build-output one for the primary deploy.
33+
# Only the old-gen manifest lists this binary; the next-gen manifest still uses the build-output updater.
34+
# Requires NEXT_ORIGIN_BASE + NEXT_SFTP_BASE_PATH to be set.
35+
COMPAT_UPDATER: tools/v1/AnakinRaW.ExternalUpdater.exe
36+
2637
jobs:
2738

2839
# Builds and tests the solution.
2940
test:
3041
uses: ./.github/workflows/test.yml
3142

43+
# End-to-end self-update test (single-channel + dual-channel via /v2/).
44+
integration-test:
45+
needs: [test]
46+
uses: ./.github/workflows/integration-test.yml
47+
3248
pack:
3349
name: Pack
3450
needs: [test]
@@ -47,8 +63,6 @@ jobs:
4763
- name: Create Net Core Release
4864
# use publish for .NET Core
4965
run: dotnet publish ${{ env.TOOL_PROJ_PATH }} --configuration Release -f net10.0 --output ./releases/net10.0 /p:DebugType=None /p:DebugSymbols=false
50-
- name: Create Linux Release
51-
run: dotnet publish ${{ env.TOOL_PROJ_PATH }} --configuration Release -f net10.0 --runtime linux-x64 --self-contained true --output ./releases/linux-x64 /p:DebugType=None /p:DebugSymbols=false
5266
- name: Upload a Build Artifact
5367
uses: actions/upload-artifact@v7
5468
with:
@@ -59,10 +73,13 @@ jobs:
5973

6074
deploy:
6175
name: Deploy
62-
# Deploy on push to main or manual trigger
76+
# Stable deploys are gated to 'main'. Non-stable channels (beta, canary, etc.) can be
77+
# workflow_dispatched from any branch.
6378
if: |
64-
(github.ref == 'refs/heads/main' && github.event_name == 'push') || github.event_name == 'workflow_dispatch'
65-
needs: [pack]
79+
(github.event_name == 'push' && github.ref == 'refs/heads/main') ||
80+
(github.event_name == 'workflow_dispatch' &&
81+
(github.event.inputs.branch != 'stable' || github.ref == 'refs/heads/main'))
82+
needs: [pack, integration-test]
6683
runs-on: ubuntu-latest
6784
steps:
6885
- name: Checkout sources
@@ -75,37 +92,37 @@ jobs:
7592
name: Binary Releases
7693
path: ./releases
7794

78-
# Deploy .NET Framework self-update release
7995
- name: Setup .NET
8096
uses: actions/setup-dotnet@v5
8197
with:
8298
dotnet-version: 10.0.x
83-
- name: Build Creator
84-
run: dotnet build ${{env.CREATOR_PROJ_PATH}} --configuration Release --output ./dev
85-
- name: Build Uploader
86-
run: dotnet build ${{env.UPLOADER_PROJ_PATH}} --configuration Release --output ./dev
87-
- name: Create binaries directory
88-
run: mkdir -p ./deploy
89-
- name: Copy self-update files
99+
100+
- name: Publish self-update release
101+
shell: pwsh
90102
run: |
91-
cp ./releases/net481/${{env.TOOL_EXE}} ./deploy/
92-
cp ./releases/net481/${{env.UPDATER_EXE}} ./deploy/
93-
- name: Create Manifest
94-
run: dotnet ./dev/${{env.MANIFEST_CREATOR}} -a deploy/${{env.TOOL_EXE}} --appDataFiles deploy/${{env.UPDATER_EXE}} --origin ${{env.ORIGIN_BASE}} -o ./deploy -b ${{env.BRANCH_NAME}}
95-
- name: Upload Build
96-
run: dotnet ./dev/${{env.SFTP_UPLOADER}} ftp --host $host --port $port -u ${{secrets.SFTP_USER}} -p ${{secrets.SFTP_PASSWORD}} --base $base_path -s $source
97-
env:
98-
host: republicatwar.com
99-
port: 1579
100-
base_path: ${{env.ORIGIN_BASE_PART}}
101-
source: ./deploy
103+
& $env:PUBLISH_SCRIPT `
104+
-AppExePath "./releases/net481/$env:TOOL_EXE" `
105+
-UpdaterExePath "./releases/net481/$env:UPDATER_EXE" `
106+
-EmbeddedTrustCertPath "$env:EMBEDDED_TRUST_CERT" `
107+
-Origin "$env:ORIGIN_BASE" `
108+
-SftpBasePath "$env:SFTP_BASE_PATH" `
109+
-Branch "$env:BRANCH_NAME" `
110+
-SigningPfxBase64 "${{ secrets.UPDATER_SIGNING_PFX_B64 }}" `
111+
-SigningPfxPassword "${{ secrets.UPDATER_SIGNING_PFX_PASSWORD }}" `
112+
-SftpHost "republicatwar.com" `
113+
-SftpPort 1579 `
114+
-SftpUser "${{ secrets.SFTP_USER }}" `
115+
-SftpPassword "${{ secrets.SFTP_PASSWORD }}" `
116+
-NextOrigin "$env:NEXT_ORIGIN_BASE" `
117+
-NextSftpBasePath "$env:NEXT_SFTP_BASE_PATH" `
118+
-CompatibilityUpdaterExePath "$env:COMPAT_UPDATER"
102119
103120
# Deploy .NET Core and .NET Framework apps to Github
104121
- name: Create NET Core .zip
105122
# Change into the artifacts directory to avoid including the directory itself in the zip archive
106123
working-directory: ./releases/net10.0
107124
run: zip -r ../ModVerify-Net10.zip .
108-
- uses: dotnet/nbgv@v0.5.1
125+
- uses: dotnet/nbgv@v0.5.2
109126
id: nbgv
110127
- name: Create GitHub release
111128
# Create a GitHub release on push to main only
@@ -117,7 +134,6 @@ jobs:
117134
tag_name: v${{ steps.nbgv.outputs.SemVer2 }}
118135
token: ${{ secrets.GITHUB_TOKEN }}
119136
generate_release_notes: true
120-
files: |
137+
files: |
121138
./releases/net481/ModVerify.exe
122-
./releases/ModVerify-Net10.zip
123-
./releases/linux-x64/ModVerify
139+
./releases/ModVerify-Net10.zip

.github/workflows/test.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,20 @@ jobs:
2626
- uses: actions/setup-dotnet@v5
2727
with:
2828
dotnet-version: 10.0.x
29-
- name: Build & Test in Release Mode
30-
run: dotnet test --configuration Release --report-github
29+
- name: Build & Test in Release Mode (Windows)
30+
if: runner.os == 'Windows'
31+
run: dotnet test --configuration Release --report-github
32+
33+
- name: Build & Test in Release Mode (Linux)
34+
if: runner.os == 'Linux'
35+
shell: bash
36+
# ExternalUpdater.App.Test is net481-only — it spawns the real ExternalUpdater.exe
37+
# and uses Windows-only helpers (cmd .bat stubs, ping.exe). It cannot run on Linux
38+
# (no mono in the runner image, and the helpers don't exist anyway). Build the
39+
# whole solution, then test every project except that one.
40+
run: |
41+
set -euo pipefail
42+
dotnet build --configuration Release
43+
for proj in $(find . -name '*.Test.csproj' -not -path '*/ExternalUpdater.App.Test/*'); do
44+
dotnet test "$proj" --no-build --configuration Release --report-github
45+
done

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
<ItemGroup>
3535
<PackageReference Update="SauceControl.InheritDoc" Version="2.0.2" />
36-
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.203" PrivateAssets="All"/>
36+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.300" PrivateAssets="All"/>
3737
<PackageReference Include="Nerdbank.GitVersioning" Condition="!Exists('packages.config')">
3838
<PrivateAssets>all</PrivateAssets>
3939
<Version>3.9.50</Version>

ModVerify.slnx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
<Solution>
2+
<Folder Name="/.github/">
3+
<File Path=".github/workflows/integration-test.yml" />
4+
<File Path=".github/workflows/release.yml" />
5+
<File Path=".github/workflows/test.yml" />
6+
</Folder>
27
<Folder Name="/ModdingToolBase/" />
38
<Folder Name="/ModdingToolBase/AnakinApps/">
49
<Project Path="modules/ModdingToolBase/src/AnakinApps/ApplicationBase.CommandLine/ApplicationBase.CommandLine.csproj" />
@@ -7,7 +12,14 @@
712
</Folder>
813
<Folder Name="/ModdingToolBase/DeployTools/">
914
<Project Path="modules/ModdingToolBase/src/AnakinApps/ApplicationManifestCreator/ApplicationManifestCreator.csproj" />
15+
<Project Path="modules/ModdingToolBase/src/AnakinApps/ApplicationManifestSigner/ApplicationManifestSigner.csproj" />
1016
<Project Path="modules/ModdingToolBase/src/AnakinApps/FtpUploader/FtpUploader.csproj" />
17+
<Project Path="modules/ModdingToolBase/test/AnakinApps/ApplicationManifestSigner.Test/ApplicationManifestSigner.Test.csproj" />
18+
</Folder>
19+
<Folder Name="/ModdingToolBase/Scripts/">
20+
<File Path="modules/ModdingToolBase/scripts/Publish-LocalRelease.ps1" />
21+
<File Path="modules/ModdingToolBase/scripts/Publish-Release.ps1" />
22+
<File Path="modules/ModdingToolBase/scripts/Test-LocalUpdateCycle.ps1" />
1123
</Folder>
1224
<Folder Name="/ModdingToolBase/UpdateFrameworks/">
1325
<Project Path="modules/ModdingToolBase/src/Updater/AppUpdaterFramework.Attributes/AppUpdaterFramework.Attributes.csproj" />
@@ -16,6 +28,13 @@
1628
<Project Path="modules/ModdingToolBase/src/Updater/ExternalUpdater.App/ExternalUpdater.App.csproj" />
1729
<Project Path="modules/ModdingToolBase/src/Updater/ExternalUpdater.Core/ExternalUpdater.Core.csproj" />
1830
</Folder>
31+
<Folder Name="/ModdingToolBase/UpdateFrameworks/test/">
32+
<Project Path="modules/ModdingToolBase/src/Updater/AppUpdaterFramework.Signing.Testing/AppUpdaterFramework.Signing.Testing.csproj" />
33+
<Project Path="modules/ModdingToolBase/test/Updater/AppUpdaterFramework.Manifest.Test/AppUpdaterFramework.Manifest.Test.csproj" />
34+
<Project Path="modules/ModdingToolBase/test/Updater/AppUpdaterFramework.Test/AppUpdaterFramework.Test.csproj" />
35+
<Project Path="modules/ModdingToolBase/test/Updater/ExternalUpdater.App.Test/ExternalUpdater.App.Test.csproj" />
36+
<Project Path="modules/ModdingToolBase/test/Updater/ExternalUpdater.Core.Test/ExternalUpdater.Core.Test.csproj" />
37+
</Folder>
1938
<Folder Name="/PetroglyphTools/">
2039
<Project Path="src/PetroglyphTools/PG.StarWarsGame.Engine.FileSystem.Test/PG.StarWarsGame.Engine.FileSystem.Test.csproj" />
2140
<Project Path="src/PetroglyphTools/PG.StarWarsGame.Engine.FileSystem/PG.StarWarsGame.Engine.FileSystem.csproj" />

deploy-local.ps1

Lines changed: 53 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,67 @@
1-
# Local deployment script for ModVerify to test the update feature.
2-
# This script builds the application, creates an update manifest, and "deploys" it to a local directory.
1+
# =========================================================================================
2+
# Local deployment to test the ModVerify update flow end-to-end.
3+
#
4+
# USAGE
5+
# .\deploy-local.ps1 # single-channel test
6+
# .\deploy-local.ps1 -DualPublish # also publish to a next-gen channel
7+
# .\deploy-local.ps1 -DualPublish -CompatibilityUpdater <path>
8+
# # primary uses compat updater;
9+
# # next-gen uses build-output updater
10+
#
11+
# -CompatibilityUpdater requires -DualPublish.
12+
# -InstalledVersion / -ServerVersion override the version pair used to set up the test.
13+
#
14+
# Builds ModVerify twice (older "installed" + newer "server"), then hands off to the shared
15+
# Publish-LocalRelease.ps1 in ModdingToolBase for cert generation, manifest signing, and
16+
# install-dir staging.
17+
# =========================================================================================
18+
19+
param(
20+
[string]$InstalledVersion = "0.0.1-local",
21+
[string]$ServerVersion = "99.99.99-local",
22+
[switch]$DualPublish,
23+
[string]$CompatibilityUpdater
24+
)
325

426
$ErrorActionPreference = "Stop"
527

628
$root = $PSScriptRoot
729
if ([string]::IsNullOrEmpty($root)) { $root = Get-Location }
830

9-
$deployRoot = Join-Path $root ".local_deploy"
10-
$stagingDir = Join-Path $deployRoot "staging"
11-
$serverDir = Join-Path $deployRoot "server"
12-
$installDir = Join-Path $deployRoot "install"
31+
. (Join-Path $root "modules\ModdingToolBase\scripts\NbgvVersion.ps1")
1332

14-
$toolProj = Join-Path $root "src\ModVerify.CliApp\ModVerify.CliApp.csproj"
15-
$creatorProj = Join-Path $root "modules\ModdingToolBase\src\AnakinApps\ApplicationManifestCreator\ApplicationManifestCreator.csproj"
16-
$uploaderProj = Join-Path $root "modules\ModdingToolBase\src\AnakinApps\FtpUploader\FtpUploader.csproj"
33+
$deployRoot = Join-Path $root ".local_deploy"
34+
$installBuildDir = Join-Path $deployRoot "bin\install"
35+
$serverBuildDir = Join-Path $deployRoot "bin\tool"
1736

18-
$toolExe = "ModVerify.exe"
19-
$updaterExe = "AnakinRaW.ExternalUpdater.exe"
20-
$manifestCreatorDll = "AnakinRaW.ApplicationManifestCreator.dll"
21-
$uploaderDll = "AnakinRaW.FtpUploader.dll"
37+
$toolProj = Join-Path $root "src\ModVerify.CliApp\ModVerify.CliApp.csproj"
38+
$baseScript = Join-Path $root "modules\ModdingToolBase\scripts\Publish-LocalRelease.ps1"
2239

23-
# 1. Clean and Create directories
2440
if (Test-Path $deployRoot) { Remove-Item -Recurse -Force $deployRoot }
25-
New-Item -ItemType Directory -Path $stagingDir | Out-Null
26-
New-Item -ItemType Directory -Path $serverDir | Out-Null
27-
New-Item -ItemType Directory -Path $installDir | Out-Null
28-
29-
Write-Host "--- Building ModVerify (net481) ---" -ForegroundColor Cyan
30-
dotnet build $toolProj --configuration Release -f net481 --output "$deployRoot\bin\tool" /p:DebugType=None /p:DebugSymbols=false
31-
32-
Write-Host "--- Building Manifest Creator ---" -ForegroundColor Cyan
33-
dotnet build $creatorProj --configuration Release --output "$deployRoot\bin\creator"
34-
35-
Write-Host "--- Building Local Uploader ---" -ForegroundColor Cyan
36-
dotnet build $uploaderProj --configuration Release --output "$deployRoot\bin\uploader"
37-
38-
# 2. Prepare staging
39-
Write-Host "--- Preparing Staging ---" -ForegroundColor Cyan
40-
Copy-Item "$deployRoot\bin\tool\$toolExe" $stagingDir
41-
Copy-Item "$deployRoot\bin\tool\$updaterExe" $stagingDir
41+
New-Item -ItemType Directory -Path $deployRoot | Out-Null
4242

43-
# 3. Create Manifest
44-
# Origin must be an absolute URI for the manifest creator.
45-
# Using 127.0.0.1 and file:// is tricky with Flurl/DownloadManager sometimes.
46-
# We'll use the local path and ensure it's formatted correctly.
47-
$serverPath = (Resolve-Path $serverDir).Path
48-
$serverUri = "file:///$($serverPath.Replace('\', '/'))"
49-
# If we have 3 slashes, Flurl/DownloadManager might still fail on Windows if it expects a certain format.
50-
# However, the ManifestCreator just needs a valid URI for the 'Origin' field in the manifest.
51-
Write-Host "--- Creating Manifest (Origin: $serverUri) ---" -ForegroundColor Cyan
52-
dotnet "$deployRoot\bin\creator\$manifestCreatorDll" `
53-
-a "$stagingDir\$toolExe" `
54-
--appDataFiles "$stagingDir\$updaterExe" `
55-
--origin "$serverUri" `
56-
-o "$stagingDir" `
57-
-b "beta"
43+
$nbgv = Backup-NbgvVersion -RepoRoot $root
44+
try {
45+
Write-Host "--- Building ModVerify (net481) @ installed v$InstalledVersion ---" -ForegroundColor Cyan
46+
Set-NbgvVersion -Snapshot $nbgv -Version $InstalledVersion
47+
dotnet build $toolProj --configuration Release -f net481 --output $installBuildDir /p:DebugType=None /p:DebugSymbols=false /p:LocalDeploy=true
5848

59-
# 4. "Deploy" to server using the local uploader
60-
Write-Host "--- Deploying to Local Server ---" -ForegroundColor Cyan
61-
dotnet "$deployRoot\bin\uploader\$uploaderDll" local --base "$serverDir" --source "$stagingDir"
49+
Write-Host "--- Building ModVerify (net481) @ server v$ServerVersion ---" -ForegroundColor Cyan
50+
Set-NbgvVersion -Snapshot $nbgv -Version $ServerVersion
51+
dotnet build $toolProj --configuration Release -f net481 --output $serverBuildDir /p:DebugType=None /p:DebugSymbols=false /p:LocalDeploy=true
6252

63-
# 5. Setup a "test" installation
64-
Write-Host "--- Setting up Test Installation ---" -ForegroundColor Cyan
65-
Copy-Item "$deployRoot\bin\tool\*" $installDir -Recurse
53+
$publishParams = @{
54+
AppExePath = Join-Path $serverBuildDir "ModVerify.exe"
55+
UpdaterExePath = Join-Path $serverBuildDir "AnakinRaW.ExternalUpdater.exe"
56+
DeployRoot = $deployRoot
57+
InstallBuildDir = $installBuildDir
58+
Branch = "beta"
59+
}
60+
if ($DualPublish) { $publishParams.DualPublish = $true }
61+
if ($CompatibilityUpdater) { $publishParams.CompatibilityUpdater = $CompatibilityUpdater }
6662

67-
Write-Host "`nLocal deployment complete!" -ForegroundColor Green
68-
Write-Host "Server directory: $serverDir"
69-
Write-Host "Install directory: $installDir"
70-
Write-Host "`nTo test the update:"
71-
Write-Host "1. (Optional) Modify the version in version.json and run this script again to 'push' a new version to the local server."
72-
Write-Host "2. Run ModVerify from the install directory with the following command:"
73-
Write-Host " cd '$installDir'"
74-
Write-Host " .\ModVerify.exe updateApplication --updateManifestUrl '$serverUri'"
75-
Write-Host "`n Note: You can also specify a different branch using --updateBranch if needed."
63+
& $baseScript @publishParams
64+
}
65+
finally {
66+
Restore-NbgvVersion -Snapshot $nbgv
67+
}

modules/ModdingToolBase

Submodule ModdingToolBase updated 212 files

0 commit comments

Comments
 (0)