Files
kefu/deploy/contact-recovery-20260918/build_contact_recovery_v1_4_28.ps1
T
2026-09-21 10:34:06 +08:00

45 lines
5.1 KiB
PowerShell

param([switch]$Finalized)
$ErrorActionPreference = 'Stop'
if (-not $Finalized) { throw 'Only run after root finalizes the contact recovery release.' }
$taskArtifactRoot = $PSScriptRoot
$taskPlan = Get-Content -Raw -LiteralPath (Join-Path $taskArtifactRoot 'contact-recovery-release-plan.json') | ConvertFrom-Json
if (-not $taskPlan.finalized -or $taskPlan.version -ne '1.4.28') { throw 'Finalized release plan required' }
$taskRequiredFrozen = @('review_assistant_contacts','review_assistant','review_state','reply_session_policy','protocol_engine','wechat_bot','reply_database','wxwork_db','voice_messages','voice_transcription','wechat_gui_qt','app_version','contact_reply_guard','contact_relation')
foreach ($taskModule in $taskRequiredFrozen) { if ($taskModule -notin $taskPlan.frozenModules) { throw ('Missing required frozen module: ' + $taskModule) } }
if ($taskPlan.windowsTestModules.Count -le 0) { throw 'Select explicit synthetic tests before building' }
$taskRoot = [IO.Path]::GetFullPath($taskPlan.windowsRoot)
if ($taskRoot.TrimEnd('\') -ne 'C:\wechat_rpa') { throw 'Validated cached builder requires C:\wechat_rpa' }
foreach ($taskModule in $taskPlan.windowsTestModules) { if (-not (Test-Path -LiteralPath (Join-Path $taskRoot ($taskModule + '.py')))) { throw ('Sync finalized test module first: ' + $taskModule) } }
if (([IO.DriveInfo]::new('C:\')).AvailableFreeSpace -lt 3500000000) { throw 'At least 3.5 GB free disk space required; do not delete user data to build' }
$taskPython = Join-Path $taskRoot '.build-venv\Scripts\python.exe'
$taskOld = Join-Path $taskRoot 'releases\甄AI客服-安装包-v1.4.27.exe'
$taskPreviousHash = '1ef5f2155992423cdb0ac3d3c0f29bcbd5f401baae13d359a98292d02c036fff'
if ($taskPlan.previousInstallerSha256 -ne $taskPreviousHash -or $taskPlan.previousVersion -ne '1.4.27') { throw 'Previous release identity in plan differs' }
if ((Get-FileHash -LiteralPath $taskOld -Algorithm SHA256).Hash.ToLowerInvariant() -ne $taskPreviousHash) { throw 'Previous release changed' }
if (Test-Path -LiteralPath (Join-Path $taskRoot 'dist\ZhenAI-WeCom-Assistant-v1.4.28')) { throw 'Refuse to overwrite existing app build' }
if (Test-Path -LiteralPath (Join-Path $taskRoot 'dist\installer\甄AI客服-安装包-v1.4.28.exe')) { throw 'Refuse to overwrite existing installer' }
if (-not (Select-String -LiteralPath (Join-Path $taskRoot 'app_version.py') -Pattern '^APP_VERSION = "1.4.28"$')) { throw 'Root must set APP_VERSION 1.4.28 before build' }
& $taskPython -B -c 'import sys,ssl,PyInstaller,PySide6,requests,numpy,PIL,pyautogui,pyperclip,win32gui,mcp,rapidocr_onnxruntime,faster_whisper,ctranslate2,av,pysilk; from Crypto.Cipher import AES; assert sys.version_info[:2] == (3,12)'
if ($LASTEXITCODE -ne 0) { throw 'Existing Python 3.12 build environment required; no automatic installs' }
$taskManifest = [ordered]@{}
$taskInputs = @(Get-ChildItem -LiteralPath $taskRoot -File | Where-Object { $_.Extension -in @('.py','.ps1','.spec') -or $_.Name -eq 'requirements.txt' }) + @(Get-ChildItem -LiteralPath (Join-Path $taskRoot 'assets') -Recurse -File)
$taskInputs += @(Get-ChildItem -LiteralPath (Join-Path $taskRoot 'tests') -Filter '*.py' -Recurse -File)
foreach ($taskFile in $taskInputs) { $taskRelative = $taskFile.FullName.Substring($taskRoot.Length + 1).Replace('\','/'); $taskManifest[$taskRelative] = (Get-FileHash -LiteralPath $taskFile.FullName -Algorithm SHA256).Hash.ToLowerInvariant() }
$taskManifestPath = Join-Path $taskArtifactRoot 'build-source-manifest.json'
if (Test-Path -LiteralPath $taskManifestPath) { throw 'Build manifest already exists' }
[IO.File]::WriteAllText($taskManifestPath, ($taskManifest | ConvertTo-Json), [Text.UTF8Encoding]::new($false))
$env:LOCALAPPDATA = Join-Path $taskArtifactRoot 'build-profile\Local'
$env:APPDATA = Join-Path $taskArtifactRoot 'build-profile\Roaming'
New-Item -ItemType Directory -Path $env:LOCALAPPDATA,$env:APPDATA -Force | Out-Null
Push-Location $taskRoot
try {
& (Join-Path $taskArtifactRoot 'build_windows_cached_contact_recovery.ps1') -PythonPath $taskPython *> (Join-Path $taskArtifactRoot 'contact-recovery-app-build.log')
if ($LASTEXITCODE -ne 0) { throw 'Application build failed' }
foreach ($taskEntry in $taskManifest.GetEnumerator()) { if ((Get-FileHash -LiteralPath (Join-Path $taskRoot $taskEntry.Key) -Algorithm SHA256).Hash.ToLowerInvariant() -ne $taskEntry.Value) { throw ('Source changed during build: '+$taskEntry.Key) } }
& (Join-Path $taskRoot 'build_installer.ps1') -SkipAppBuild *> (Join-Path $taskArtifactRoot 'contact-recovery-installer-build.log')
if ($LASTEXITCODE -ne 0) { throw 'Installer build failed' }
foreach ($taskEntry in $taskManifest.GetEnumerator()) { if ((Get-FileHash -LiteralPath (Join-Path $taskRoot $taskEntry.Key) -Algorithm SHA256).Hash.ToLowerInvariant() -ne $taskEntry.Value) { throw ('Source changed while creating installer: '+$taskEntry.Key) } }
if ((Get-FileHash -LiteralPath $taskOld -Algorithm SHA256).Hash.ToLowerInvariant() -ne $taskPreviousHash) { throw 'Previous release changed' }
} finally { Pop-Location }
Write-Output 'Built v1.4.28 locally. Validation required; no install/upload/publication performed.'