param( [string]$Remote = "git@gitea.itworx.tech:Jens/ForgeFlow.git", [string]$Branch = "main", [string]$InstalledSource = "C:\Projects\ForgeFlow" ) $ErrorActionPreference = "Stop" $source = $PSScriptRoot $manifestPath = Join-Path $source "package.json" if (-not (Test-Path -LiteralPath $manifestPath)) { throw "package.json was not found beside the publishing script." } $manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json if ($manifest.name -ne "forgeflow") { throw "Run this script from an extracted ForgeFlow source release." } $version = [string]$manifest.version $temp = Join-Path ([IO.Path]::GetTempPath()) ("forgeflow-publish-" + [guid]::NewGuid().ToString("N")) $clone = Join-Path $temp "ForgeFlow" $publishedCommit = $null try { Write-Host "Validating ForgeFlow $version before publishing..." -ForegroundColor Cyan Push-Location $source try { & cmd.exe /d /s /c "npm install --no-audit --no-fund" if ($LASTEXITCODE -ne 0) { throw "npm install failed." } if (-not (Test-Path -LiteralPath (Join-Path $source "package-lock.json"))) { throw "npm install did not create package-lock.json; publication was stopped to avoid a non-reproducible update." } & cmd.exe /d /s /c "npm run check" if ($LASTEXITCODE -ne 0) { throw "ForgeFlow quality gate failed." } } finally { Pop-Location } New-Item -ItemType Directory -Force -Path $temp | Out-Null Write-Host "Cloning $Remote..." -ForegroundColor Cyan & git clone --branch $Branch --single-branch $Remote $clone if ($LASTEXITCODE -ne 0) { throw "Could not clone the ForgeFlow update repository." } & robocopy.exe $source $clone /MIR /R:2 /W:1 /NFL /NDL /NJH /NJS /NP /XD .git node_modules dist /XF *.zip *.sha256 if ($LASTEXITCODE -gt 7) { throw "Robocopy failed with exit code $LASTEXITCODE." } Push-Location $clone try { & git add -A if ($LASTEXITCODE -ne 0) { throw "Could not stage the release source." } $changes = @(& git status --porcelain) if ($changes.Count -gt 0) { & git commit -m "Release ForgeFlow $version" if ($LASTEXITCODE -ne 0) { throw "Could not create the release commit." } & git push origin $Branch if ($LASTEXITCODE -ne 0) { throw "Could not push ForgeFlow $version to Gitea." } } else { Write-Host "Gitea already contains the ForgeFlow $version source; verifying the branch head." -ForegroundColor Yellow } $localCommit = (& git rev-parse HEAD).Trim() if ($LASTEXITCODE -ne 0 -or $localCommit -notmatch '^[0-9a-f]{40}$') { throw "Could not read the local release commit." } $remoteLines = @(& git ls-remote origin "refs/heads/$Branch") if ($LASTEXITCODE -ne 0 -or $remoteLines.Count -lt 1) { throw "Could not verify the Gitea release branch." } $publishedCommit = ($remoteLines[0] -split "`t")[0].Trim() if ($publishedCommit -ne $localCommit) { throw "Gitea did not report the exact release commit after publication." } } finally { Pop-Location } Write-Host "ForgeFlow $version is available on Gitea at commit $($publishedCommit.Substring(0,7))." -ForegroundColor Green $installedManifestPath = Join-Path $InstalledSource "package.json" if (Test-Path -LiteralPath $installedManifestPath) { try { $installedManifest = Get-Content -LiteralPath $installedManifestPath -Raw | ConvertFrom-Json if ($installedManifest.name -eq "forgeflow" -and [string]$installedManifest.version -ne $version) { $bootstrapSource = Join-Path $source "scripts\apply-source-update.ps1" $bootstrapTarget = Join-Path $InstalledSource "scripts\apply-source-update.ps1" $bootstrapText = Get-Content -LiteralPath $bootstrapSource -Raw if ($bootstrapText.TrimStart() -notmatch '^param\(') { throw "The validated updater bootstrap does not start with param(." } New-Item -ItemType Directory -Force -Path (Split-Path -Parent $bootstrapTarget) | Out-Null Copy-Item -LiteralPath $bootstrapSource -Destination $bootstrapTarget -Force $copiedText = Get-Content -LiteralPath $bootstrapTarget -Raw if ($copiedText.TrimStart() -notmatch '^param\(') { throw "The updater bootstrap copy failed validation." } Write-Host "Prepared the installed ForgeFlow $($installedManifest.version) updater helper without changing its version." -ForegroundColor Green } } catch { throw "Release was published, but the installed updater bootstrap could not be prepared: $($_.Exception.Message)" } } else { Write-Host "Installed source was not found at $InstalledSource; publication itself succeeded." -ForegroundColor Yellow } Write-Host "Open the installed older ForgeFlow and use Settings -> ForgeFlow updates -> Check now." -ForegroundColor Cyan } finally { Remove-Item -LiteralPath $temp -Recurse -Force -ErrorAction SilentlyContinue }