Files
pyramid/scripts/release.ps1
T
Bernd Steckmeister fe6427bfba security: geleakte Secrets aus Repo entfernen (Review-Befund k)
Secret-Scan im Fable-5-Review fand vier aktive Zugangsdaten im
oeffentlich erreichbaren Gitea-Repo. Gefahrlos entfernbare Stellen:
- scripts/release.ps1: Gitea-Token -> Umgebungsvariable PYRAMID_GITEA_TOKEN
- docs/matrix-sdk/13-server-admin: 19x Admin-Token -> <ADMIN_TOKEN>

Client-eingebettete Secrets (LiveKit apiSecret, Admin-Token im
E2EE-Diagnose-Upload, Giphy-Key) brauchen Rotation + Server-Umbau
und stehen als neue M0-ROADMAP-Punkte (nicht blind auf dem Pi fixbar).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 03:32:37 +02:00

212 lines
10 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Pyramid Release Script
# Usage: .\scripts\release.ps1
# Builds Windows + Android, creates Gitea release, uploads artifacts.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# Always run from the project root, regardless of where the script was called from.
Set-Location (Split-Path $PSScriptRoot -Parent)
# ── Config ────────────────────────────────────────────────────────────────────
$GiteaBase = "http://192.168.178.71:3000"
$GiteaRepo = "steggi/pyramid"
# Token NIE hier eintragen (CLAUDE.md: keine Secrets ins Repo). Er kommt aus der
# Umgebungsvariable PYRAMID_GITEA_TOKEN einmalig pro PC setzen mit:
# [Environment]::SetEnvironmentVariable("PYRAMID_GITEA_TOKEN", "<token>", "User")
# (neues Terminal öffnen, damit die Variable sichtbar ist)
$GiteaToken = $env:PYRAMID_GITEA_TOKEN
if ([string]::IsNullOrWhiteSpace($GiteaToken)) {
Write-Error ("PYRAMID_GITEA_TOKEN ist nicht gesetzt. Einmalig setzen mit:`n" +
' [Environment]::SetEnvironmentVariable("PYRAMID_GITEA_TOKEN", "<token>", "User")' +
"`nDen Token in Gitea unter Einstellungen > Anwendungen erzeugen (Scope: repository).")
exit 1
}
$Headers = @{ Authorization = "token $GiteaToken"; "Content-Type" = "application/json" }
# ── Read and Update version from pubspec.yaml ─────────────────────────────────
$pubspecPath = "pubspec.yaml"
$pubspecLines = @(Get-Content $pubspecPath)
$versionIndex = -1
for ($i = 0; $i -lt $pubspecLines.Count; $i++) {
if ($pubspecLines[$i] -match "^version:") {
$versionIndex = $i
break
}
}
if ($versionIndex -lt 0) { Write-Error "version not found in pubspec.yaml"; exit 1 }
$currentVersionFull = ($pubspecLines[$versionIndex] -split ":")[1].Trim()
$currentVersion = $currentVersionFull.Split("+")[0]
$currentBuild = 0
if ($currentVersionFull -match "\+") {
$currentBuild = [int]$currentVersionFull.Split("+")[1]
}
$vParts = $currentVersion.Split(".")
$major = [int]$vParts[0]
$minor = [int]$vParts[1]
$patch = [int]$vParts[2]
$nextPatch = "$major.$minor.$($patch + 1)"
$nextBuild = $currentBuild + 1
Write-Host ""
Write-Host " Aktuelle Version : $currentVersion (Build $currentBuild)" -ForegroundColor Cyan
$newVersionInput = Read-Host " Neue Version eingeben (Leer lassen für $nextPatch)"
if ([string]::IsNullOrWhiteSpace($newVersionInput)) {
$newVersion = $nextPatch
} else {
$newVersion = $newVersionInput.Trim().TrimStart("v")
}
$newVersionFull = "$newVersion+$nextBuild"
if ($newVersionFull -ne $currentVersionFull) {
$pubspecLines[$versionIndex] = "version: $newVersionFull"
Set-Content -Path $pubspecPath -Value $pubspecLines
Write-Host " pubspec.yaml auf $newVersionFull aktualisiert." -ForegroundColor Green
}
$version = $newVersion
$tag = "v$version"
Write-Host ""
Write-Host " Pyramid Release Builder" -ForegroundColor Cyan
Write-Host " Version : $tag" -ForegroundColor White
Write-Host ""
# ── Check for existing release ────────────────────────────────────────────────
try {
$existing = Invoke-RestMethod "$GiteaBase/api/v1/repos/$GiteaRepo/releases/tags/$tag" `
-Headers $Headers -Method Get -ErrorAction Stop
Write-Host " [!] Release $tag existiert bereits auf Gitea." -ForegroundColor Yellow
$overwrite = Read-Host " Überschreiben? (j/N)"
if ($overwrite -notmatch "^[jJ]$") { Write-Host " Abgebrochen."; exit 0 }
# Delete existing release
Invoke-RestMethod "$GiteaBase/api/v1/repos/$GiteaRepo/releases/$($existing.id)" `
-Headers $Headers -Method Delete | Out-Null
Write-Host " Alter Release gelöscht." -ForegroundColor Gray
} catch {
# 404 = release doesn't exist, that's fine
}
# ── Release notes ─────────────────────────────────────────────────────────────
Write-Host " Release-Notizen (leer lassen = Changelog aus Git-Commits):" -ForegroundColor Cyan
$notes = Read-Host " > "
if ([string]::IsNullOrWhiteSpace($notes)) {
# Auto-generate from git log since last tag.
# git describe exits non-zero when no tags exist; catch the error explicitly
# because $ErrorActionPreference = "Stop" would otherwise abort the script.
$lastTag = $null
try { $lastTag = git describe --tags --abbrev=0 HEAD^ 2>$null } catch {}
if ($lastTag) {
$notes = git log "$lastTag..HEAD" --pretty=format:"- %s" 2>$null | Out-String
} else {
$notes = git log --pretty=format:"- %s" -20 2>$null | Out-String
}
Write-Host " (Commits als Release-Notizen verwendet)" -ForegroundColor Gray
}
# ── Build Windows ─────────────────────────────────────────────────────────────
Write-Host ""
Write-Host " [1/4] Windows Build..." -ForegroundColor Cyan
flutter build windows --release
if ($LASTEXITCODE -ne 0) { Write-Error "Windows build fehlgeschlagen"; exit 1 }
$winSrc = "build\windows\x64\runner\Release"
$winZip = "build\pyramid-windows-$tag.zip"
if (Test-Path $winZip) { Remove-Item $winZip -Force }
Compress-Archive -Path "$winSrc\*" -DestinationPath $winZip
Write-Host " Windows ZIP: $winZip" -ForegroundColor Green
# ── Build Android ─────────────────────────────────────────────────────────────
Write-Host ""
Write-Host " [2/4] Android Build (split per ABI)..." -ForegroundColor Cyan
flutter build apk --release --split-per-abi
if ($LASTEXITCODE -ne 0) { Write-Error "Android build fehlgeschlagen"; exit 1 }
# Order matters: arm64-v8a is uploaded first so app versions that still pick
# the first APK asset (pre-ABI-aware updater) get the variant that fits
# practically every real device.
$abiBuilds = @(
@{ Abi = "arm64-v8a"; Desc = "64-bit ARM — praktisch jedes Smartphone der letzten ~8 Jahre. Im Zweifel diese Datei." },
@{ Abi = "armeabi-v7a"; Desc = "32-bit ARM — sehr alte Geräte" },
@{ Abi = "x86_64"; Desc = "Emulatoren / x86-Geräte" }
)
$apkFiles = @()
foreach ($b in $abiBuilds) {
$abi = $b.Abi
$src = "build\app\outputs\flutter-apk\app-$abi-release.apk"
if (-not (Test-Path $src)) { Write-Error "APK fehlt: $src"; exit 1 }
$dst = "build\pyramid-android-$abi-$tag.apk"
Copy-Item $src $dst -Force
$apkFiles += @{ Path = $dst; Name = "pyramid-android-$abi-$tag.apk"; Desc = $b.Desc }
$sizeMb = [math]::Round((Get-Item $dst).Length / 1MB, 1)
Write-Host " Android APK ($abi, $sizeMb MB): $dst" -ForegroundColor Green
}
# Append a download guide to the release notes so every asset is explained.
$downloadGuide = "`n`n## Downloads`n`n| Datei | Für welches Gerät? |`n|---|---|`n"
foreach ($f in $apkFiles) {
$downloadGuide += "| ``$($f.Name)`` | $($f.Desc) |`n"
}
$downloadGuide += "| ``pyramid-windows-$tag.zip`` | Windows 10/11 |`n"
$downloadGuide += "`n*Die App lädt beim automatischen Update selbst die passende Variante.*"
$notes = $notes.Trim() + $downloadGuide
# ── Git tag ───────────────────────────────────────────────────────────────────
Write-Host ""
Write-Host " [3/4] Git Tag $tag..." -ForegroundColor Cyan
git tag -f $tag
# Token in die Push-URL einbetten, damit keine interaktive Passwort-Abfrage nötig ist
$pushUrl = $GiteaBase -replace "http://", "http://steggi:$GiteaToken@"
& git push "$pushUrl/steggi/pyramid.git" $tag --force
if ($LASTEXITCODE -ne 0) {
Write-Host " [!] Tag-Push fehlgeschlagen (Release wird trotzdem erstellt)." -ForegroundColor Yellow
} else {
Write-Host " Tag gepusht." -ForegroundColor Green
}
# ── Create Gitea release ──────────────────────────────────────────────────────
Write-Host ""
Write-Host " [4/4] Gitea Release erstellen..." -ForegroundColor Cyan
$body = @{
tag_name = $tag
name = "Pyramid $tag"
body = $notes.Trim()
draft = $false
prerelease = $false
target_commitish = "master"
} | ConvertTo-Json -Compress
$release = Invoke-RestMethod "$GiteaBase/api/v1/repos/$GiteaRepo/releases" `
-Headers $Headers -Method Post -Body $body
$releaseId = $release.id
Write-Host " Release ID: $releaseId" -ForegroundColor Gray
# ── Upload artifacts ──────────────────────────────────────────────────────────
function Upload-Asset($filePath, $fileName) {
# curl.exe (built into Windows 10+) handles large binary uploads reliably.
$uri = "$GiteaBase/api/v1/repos/$GiteaRepo/releases/$releaseId/assets?name=$fileName"
$result = & curl.exe -s --fail -w "%{http_code}" `
-X POST $uri `
-H "Authorization: token $GiteaToken" `
-F "attachment=@`"$filePath`""
if ($LASTEXITCODE -ne 0) {
Write-Error "Upload fehlgeschlagen ($result): $fileName"
}
Write-Host " Hochgeladen: $fileName" -ForegroundColor Green
}
# APKs first (arm64-v8a leads — see comment at $abiBuilds), then Windows.
foreach ($f in $apkFiles) {
Upload-Asset $f.Path $f.Name
}
Upload-Asset $winZip "pyramid-windows-$tag.zip"
# ── Done ──────────────────────────────────────────────────────────────────────
Write-Host ""
Write-Host " Release $tag erfolgreich erstellt!" -ForegroundColor Green
Write-Host " $GiteaBase/$GiteaRepo/releases/tag/$tag" -ForegroundColor Cyan
Write-Host ""