Manifestbasierter Production-Updater 3.3, Modulnavigation, optionales Produktbild Studio, Listing-Studio-Aktionsleiste sowie plattformübergreifende Windows-/Linux-Release-Gates.
141 lines
5.7 KiB
PowerShell
141 lines
5.7 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory=$true)][string]$CoreScript,
|
|
[Parameter(Mandatory=$true)][string]$StatusFile,
|
|
[Parameter(Mandatory=$true)][string]$EventFile,
|
|
[Parameter(Mandatory=$true)][string]$InputFile,
|
|
[Parameter(Mandatory=$true)][string]$CancelFile,
|
|
[Parameter(Mandatory=$true)][string]$SessionFile,
|
|
[Parameter(Mandatory=$true)][string]$LogFile,
|
|
[switch]$SkipProductionDeploy,
|
|
[switch]$SelfTest,
|
|
[string]$SelfTestFailAt = ''
|
|
)
|
|
|
|
Set-StrictMode -Version 2.0
|
|
$ErrorActionPreference = 'Stop'
|
|
$TargetVersion = '1.43.0'
|
|
$UpdaterVersion = '3.3.0'
|
|
|
|
function Get-DefaultSteps {
|
|
return @(
|
|
[ordered]@{id='package';title='Paket prüfen';state='pending'},
|
|
[ordered]@{id='tools';title='System prüfen';state='pending'},
|
|
[ordered]@{id='github';title='GitHub verbinden';state='pending'},
|
|
[ordered]@{id='production';title='Produktion vorbereiten';state='pending'},
|
|
[ordered]@{id='workspace';title='Arbeitskopie erstellen';state='pending'},
|
|
[ordered]@{id='tests';title='Vollständig testen';state='pending'},
|
|
[ordered]@{id='pullrequest';title='Pull Request erstellen';state='pending'},
|
|
[ordered]@{id='merge';title='Sicher mergen';state='pending'},
|
|
[ordered]@{id='deploy';title='Coolify deployen';state='pending'},
|
|
[ordered]@{id='verify';title='Produktion bestätigen';state='pending'}
|
|
)
|
|
}
|
|
|
|
function Append-HostLog([string]$Level,[string]$Message) {
|
|
try {
|
|
$parent = Split-Path -Parent $LogFile
|
|
if ($parent) { New-Item -ItemType Directory -Path $parent -Force | Out-Null }
|
|
$line = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff') [$Level] $Message$([Environment]::NewLine)"
|
|
[IO.File]::AppendAllText($LogFile,$line,(New-Object Text.UTF8Encoding($false)))
|
|
} catch {}
|
|
}
|
|
|
|
function Write-HostStatus([string]$State,[string]$Phase,[string]$Detail,[string]$ErrorText='',[string]$Remediation='') {
|
|
try {
|
|
$percent = 1
|
|
if ($State -in @('failed','cancelled','success')) { $percent = 100 }
|
|
$payload = [ordered]@{
|
|
version=$TargetVersion
|
|
updaterVersion=$UpdaterVersion
|
|
percent=$percent
|
|
phase=$Phase
|
|
detail=$Detail
|
|
state=$State
|
|
error=$ErrorText
|
|
remediation=$Remediation
|
|
updatedAt=(Get-Date).ToString('o')
|
|
logFile=$LogFile
|
|
sessionFile=$SessionFile
|
|
steps=(Get-DefaultSteps)
|
|
request=$null
|
|
} | ConvertTo-Json -Depth 8
|
|
$parent = Split-Path -Parent $StatusFile
|
|
if ($parent) { New-Item -ItemType Directory -Path $parent -Force | Out-Null }
|
|
$tmp = "$StatusFile.$PID.host.tmp"
|
|
[IO.File]::WriteAllText($tmp,$payload,(New-Object Text.UTF8Encoding($false)))
|
|
Move-Item -LiteralPath $tmp -Destination $StatusFile -Force
|
|
} catch {
|
|
Append-HostLog 'HOST-ERROR' "Status konnte nicht geschrieben werden: $($_.Exception.ToString())"
|
|
}
|
|
}
|
|
|
|
try {
|
|
foreach($path in @($StatusFile,$EventFile,$InputFile,$CancelFile,$SessionFile,$LogFile)) {
|
|
$parent = Split-Path -Parent $path
|
|
if ($parent) { New-Item -ItemType Directory -Path $parent -Force | Out-Null }
|
|
}
|
|
if (-not (Test-Path -LiteralPath $CoreScript -PathType Leaf)) {
|
|
throw "Worker-Core fehlt: $CoreScript"
|
|
}
|
|
|
|
Append-HostLog 'HOST' "Worker-Host $UpdaterVersion gestartet. Core: $CoreScript"
|
|
Write-HostStatus 'running' 'PowerShell-Parserprüfung' 'Der Worker-Kern wird vor der Ausführung mit dem echten PowerShell-Parser geprüft.'
|
|
|
|
$parserTokens = $null
|
|
$parserErrors = $null
|
|
[void][System.Management.Automation.Language.Parser]::ParseFile($CoreScript,[ref]$parserTokens,[ref]$parserErrors)
|
|
if ($parserErrors -and $parserErrors.Count -gt 0) {
|
|
$details = @($parserErrors | ForEach-Object {
|
|
"{0}:{1}:{2} {3}" -f $_.Extent.File,$_.Extent.StartLineNumber,$_.Extent.StartColumnNumber,$_.Message
|
|
}) -join [Environment]::NewLine
|
|
throw "PowerShell-Parserprüfung des Worker-Kerns fehlgeschlagen.$([Environment]::NewLine)$details"
|
|
}
|
|
Append-HostLog 'HOST' 'PowerShell-Parserprüfung des Worker-Kerns erfolgreich.'
|
|
Write-HostStatus 'running' 'Worker wird gestartet' 'Der geprüfte Worker-Kern wird geladen.'
|
|
|
|
$invokeParams = @{
|
|
StatusFile=$StatusFile
|
|
EventFile=$EventFile
|
|
InputFile=$InputFile
|
|
CancelFile=$CancelFile
|
|
SessionFile=$SessionFile
|
|
LogFile=$LogFile
|
|
}
|
|
if ($SkipProductionDeploy) { $invokeParams.SkipProductionDeploy = $true }
|
|
if ($SelfTest) { $invokeParams.SelfTest = $true }
|
|
if ($SelfTestFailAt) { $invokeParams.SelfTestFailAt = $SelfTestFailAt }
|
|
|
|
& $CoreScript @invokeParams
|
|
|
|
$terminal = $false
|
|
$stateName = ''
|
|
if (Test-Path -LiteralPath $StatusFile) {
|
|
try {
|
|
$final = Get-Content -LiteralPath $StatusFile -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
$stateName = [string]$final.state
|
|
$terminal = $stateName -in @('success','failed','cancelled')
|
|
} catch {
|
|
Append-HostLog 'HOST-ERROR' "Abschlussstatus ist nicht lesbar: $($_.Exception.Message)"
|
|
}
|
|
}
|
|
|
|
if (-not $terminal) {
|
|
$message = 'Der Update-Kern wurde beendet, ohne einen terminalen Status zu schreiben.'
|
|
Append-HostLog 'HOST-ERROR' $message
|
|
Write-HostStatus 'failed' 'Update-Kern unvollständig beendet' $message $message 'Das Protokoll enthält jetzt die vollständige Start- und Worker-Diagnose. Es wurden keine stillen Fehler verworfen.'
|
|
} else {
|
|
Append-HostLog 'HOST' "Worker-Core regulär beendet. Status: $stateName"
|
|
}
|
|
exit 0
|
|
}
|
|
catch {
|
|
$full = $_.Exception.ToString()
|
|
$message = $_.Exception.Message
|
|
Append-HostLog 'HOST-FATAL' $full
|
|
Write-HostStatus 'failed' 'Worker konnte nicht initialisiert werden' $message $full 'Der Fehler entstand vor oder beim Laden des Worker-Kerns. Protokoll öffnen zeigt die vollständige PowerShell-Ausnahme einschließlich Datei und Zeile.'
|
|
try { [Console]::Error.WriteLine($full) } catch {}
|
|
Start-Sleep -Milliseconds 350
|
|
exit 1
|
|
}
|