Files
shopPRO/build-update.ps1
Jacek 312367a3ea fix: naprawiono encoding changelog-data.html (1.2GB → 91KB) i build-update.ps1
Get-Content bez -Encoding UTF8 psuło polskie znaki przy każdym buildzie,
powodując wykładnicze powiększanie pliku. Zamieniono na ReadAllText(UTF8).
Plik changelog-data.html wygenerowany od nowa z docs/CHANGELOG.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 09:59:49 +01:00

407 lines
12 KiB
PowerShell

<#
.SYNOPSIS
Automatyczne budowanie paczki aktualizacji shopPRO na podstawie git diff miedzy tagami.
.DESCRIPTION
Skrypt porownuje dwa tagi git, filtruje pliki przez .updateignore,
tworzy ZIP + manifest JSON i aktualizuje changelog.php oraz versions.php.
.PARAMETER FromTag
Tag poczatkowy (np. v0.299). Domyslnie: ostatni tag.
.PARAMETER ToTag
Tag docelowy (np. v0.300). Wymagany.
.PARAMETER ChangelogEntry
Wpis do changelogu. Wymagany (chyba ze -DryRun).
.PARAMETER DryRun
Tylko pokaz co zostaloby zrobione, bez tworzenia plikow.
.EXAMPLE
./build-update.ps1 -ToTag v0.300 -ChangelogEntry "NEW - Manifest-based update system"
./build-update.ps1 -FromTag v0.299 -ToTag v0.300 -ChangelogEntry "NEW - opis" -DryRun
#>
param(
[string]$FromTag = "",
[Parameter(Mandatory=$true)]
[string]$ToTag,
[string]$ChangelogEntry = "",
[switch]$DryRun
)
$ErrorActionPreference = "Stop"
$Utf8NoBom = New-Object System.Text.UTF8Encoding $false
# --- Helpers ---
function Write-Step($msg) {
Write-Host " [*] $msg" -ForegroundColor Cyan
}
function Write-Ok($msg) {
Write-Host " [OK] $msg" -ForegroundColor Green
}
function Write-Warn($msg) {
Write-Host " [!] $msg" -ForegroundColor Yellow
}
function Write-Err($msg) {
Write-Host " [ERROR] $msg" -ForegroundColor Red
}
# --- 1. Walidacja tagow ---
Write-Host "`n=== shopPRO Build Update ===" -ForegroundColor White
if (-not $FromTag) {
$FromTag = (git describe --tags --abbrev=0 2>$null)
if (-not $FromTag) {
Write-Err "Nie znaleziono zadnego taga. Uzyj parametru -FromTag."
exit 1
}
Write-Step "Auto-detect FromTag: $FromTag"
}
# Sprawdz czy tagi istnieja
$tagExists = git tag -l $FromTag
if (-not $tagExists) {
Write-Err "Tag '$FromTag' nie istnieje."
exit 1
}
$toTagExists = git tag -l $ToTag
if (-not $toTagExists) {
Write-Warn "Tag '$ToTag' nie istnieje. Uzywam HEAD jako punktu docelowego."
$diffTarget = "HEAD"
} else {
$diffTarget = $ToTag
}
# --- 2. Wersja i katalog ---
$versionNumber = $ToTag -replace '^v', ''
$versionInt = [int]($versionNumber -replace '^0\.', '')
# Oblicz katalog: 0.001-0.009 -> 0.00, 0.010-0.099 -> 0.00, 0.100-0.199 -> 0.10, 0.200-0.299 -> 0.20, 0.300-0.399 -> 0.30
$dirTens = [math]::Floor($versionInt / 100)
$dirStr = "0.{0}0" -f ($dirTens * 10).ToString().PadLeft(1, '0')
# Format: jesli dirTens < 10 to "0.X0", np 0.00, 0.10, 0.20, 0.30
if ($dirTens -lt 10) {
$dirStr = "0.{0}0" -f $dirTens.ToString().PadLeft(1, '0')
} else {
$dirStr = "0.{0}0" -f $dirTens
}
Write-Step "Wersja: $versionNumber (int: $versionInt)"
Write-Step "Katalog: updates/$dirStr/"
# --- 3. Git diff ---
Write-Step "Porownywanie: $FromTag..$diffTarget"
$diffOutput = git diff --name-status "$FromTag..$diffTarget" 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Err "git diff nie powiodl sie: $diffOutput"
exit 1
}
$addedFiles = @()
$modifiedFiles = @()
$deletedFiles = @()
$renamedFiles = @()
foreach ($line in ($diffOutput -split "`n")) {
$line = $line.Trim()
if (-not $line) { continue }
$parts = $line -split "`t"
$status = $parts[0]
$filePath = if ($parts.Count -gt 1) { $parts[1] } else { "" }
# Zamien backslash na slash
$filePath = $filePath -replace '\\', '/'
switch -Wildcard ($status) {
"A" { $addedFiles += $filePath }
"M" { $modifiedFiles += $filePath }
"D" { $deletedFiles += $filePath }
"R*" {
# Rename: stary plik = deleted, nowy = added
$newPath = if ($parts.Count -gt 2) { $parts[2] -replace '\\', '/' } else { "" }
$deletedFiles += $filePath
if ($newPath) { $addedFiles += $newPath }
}
}
}
Write-Step "Zmiany: A=$($addedFiles.Count), M=$($modifiedFiles.Count), D=$($deletedFiles.Count)"
# --- 4. Filtrowanie przez .updateignore ---
$ignorePatterns = @()
$ignoreFile = ".updateignore"
if (Test-Path $ignoreFile) {
$ignorePatterns = Get-Content $ignoreFile | ForEach-Object { $_.Trim() } | Where-Object { $_ -and ($_ -notmatch '^\s*#') }
Write-Step "Zaladowano $($ignorePatterns.Count) wzorcow z .updateignore"
}
function Test-Ignored {
param([string]$FilePath)
foreach ($pattern in $ignorePatterns) {
# Wzorzec katalogu (konczy sie na /)
if ($pattern.EndsWith('/')) {
$dirPattern = $pattern.TrimEnd('/')
if ($FilePath -like "$dirPattern/*" -or $FilePath -eq $dirPattern) {
return $true
}
}
# Wzorzec z wildcard
elseif ($pattern.Contains('*')) {
# *.md -> dopasuj nazwe pliku
if ($pattern.StartsWith('*')) {
$fileName = Split-Path $FilePath -Leaf
if ($fileName -like $pattern) { return $true }
}
# Zwykly glob
elseif ($FilePath -like $pattern) { return $true }
}
# Dokladne dopasowanie
else {
if ($FilePath -eq $pattern) { return $true }
}
}
return $false
}
$filteredAdded = @()
$filteredModified = @()
$filteredDeleted = @()
$ignoredCount = 0
foreach ($f in $addedFiles) {
if (Test-Ignored $f) { $ignoredCount++; continue }
$filteredAdded += $f
}
foreach ($f in $modifiedFiles) {
if (Test-Ignored $f) { $ignoredCount++; continue }
$filteredModified += $f
}
foreach ($f in $deletedFiles) {
if (Test-Ignored $f) { $ignoredCount++; continue }
$filteredDeleted += $f
}
Write-Step "Po filtrowaniu: A=$($filteredAdded.Count), M=$($filteredModified.Count), D=$($filteredDeleted.Count) (pominieto: $ignoredCount)"
# Rozdziel usuniete pliki i katalogi
$deletedDirs = @()
$deletedFilesOnly = @()
foreach ($f in $filteredDeleted) {
# Sprawdz czy to byl katalog (w git nie ma katalogow, ale mozemy sprawdzic po wzorcu)
# Git nie trackuje pustych katalogow, wiec deleted entries to zawsze pliki
$deletedFilesOnly += $f
}
# --- 5. Odczyt migracji SQL ---
$sqlQueries = @()
$migrationFile = "migrations/$versionNumber.sql"
if (Test-Path $migrationFile) {
# Read entire file, strip comment lines, split by semicolons to get complete SQL statements
$rawLines = Get-Content $migrationFile | Where-Object { $_.Trim() -ne '' -and $_.Trim() -notmatch '^\s*--' }
$rawSql = ($rawLines -join "`n").Trim()
$sqlQueries = @($rawSql -split ';' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' } | ForEach-Object { $_.ToString() })
Write-Step "Znaleziono migracje SQL: $migrationFile ($($sqlQueries.Count) zapytan)"
} else {
Write-Step "Brak migracji SQL ($migrationFile nie istnieje)"
}
# --- 6. Podsumowanie ---
$filesToPack = $filteredAdded + $filteredModified
if ($filesToPack.Count -eq 0 -and $filteredDeleted.Count -eq 0 -and $sqlQueries.Count -eq 0) {
Write-Warn "Brak zmian do pakowania (po filtrowaniu). Przerywam."
exit 0
}
Write-Host "`n--- Pliki do paczki ---" -ForegroundColor White
foreach ($f in $filteredAdded) { Write-Host " A $f" -ForegroundColor Green }
foreach ($f in $filteredModified) { Write-Host " M $f" -ForegroundColor Yellow }
foreach ($f in $filteredDeleted) { Write-Host " D $f" -ForegroundColor Red }
if ($sqlQueries.Count -gt 0) {
Write-Host "`n--- SQL ---" -ForegroundColor White
foreach ($q in $sqlQueries) { Write-Host " $q" -ForegroundColor Gray }
}
# --- DryRun? ---
if ($DryRun) {
Write-Host "`n[DRY RUN] Zadne pliki nie zostaly utworzone.`n" -ForegroundColor Magenta
exit 0
}
# --- 7. Walidacja ChangelogEntry ---
if (-not $ChangelogEntry) {
Write-Err "Parametr -ChangelogEntry jest wymagany (chyba ze uzywasz -DryRun)."
exit 1
}
# --- 8. Tworzenie temp i kopiowanie plikow ---
$tempDir = "$env:TEMP\shopPRO_build_$versionInt"
if (Test-Path $tempDir) {
Remove-Item -Recurse -Force $tempDir
}
if (-not (Test-Path $tempDir)) {
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
}
foreach ($f in $filesToPack) {
$destPath = Join-Path $tempDir $f
$destDir = Split-Path $destPath -Parent
if (-not (Test-Path $destDir)) {
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
}
if (Test-Path $f) {
Copy-Item $f $destPath -Force
} else {
Write-Warn "Plik nie istnieje (moze zostal usuniety po TAGU): $f"
}
}
Write-Ok "Skopiowano $($filesToPack.Count) plikow do $tempDir"
# --- 9. Tworzenie ZIP ---
$updatesDir = "updates/$dirStr"
if (-not (Test-Path $updatesDir)) {
New-Item -ItemType Directory -Path $updatesDir -Force | Out-Null
}
$zipPath = "$updatesDir/ver_$versionNumber.zip"
if (Test-Path $zipPath) {
Remove-Item $zipPath -Force
}
# Pakuj zawartosc temp dir (bez folderu temp/)
$originalLocation = Get-Location
$absoluteZipPath = Join-Path $originalLocation $zipPath
Set-Location $tempDir
$tempItems = Get-ChildItem -Force
if ($tempItems) {
Compress-Archive -Path '*' -DestinationPath $absoluteZipPath -Force
} else {
# SQL-only update: create minimal ZIP with empty placeholder
$placeholderPath = "_sql_only_update.txt"
Set-Content -Path $placeholderPath -Value "SQL-only update $versionNumber"
Compress-Archive -Path $placeholderPath -DestinationPath $absoluteZipPath -Force
Remove-Item $placeholderPath -Force
}
Set-Location $originalLocation
Write-Ok "Utworzono ZIP: $zipPath"
# --- 10. Checksum SHA256 ---
$hash = (Get-FileHash $zipPath -Algorithm SHA256).Hash.ToLower()
Write-Ok "SHA256: $hash"
# --- 11. Manifest JSON ---
$manifest = @{
version = $versionNumber
date = (Get-Date -Format "yyyy-MM-dd")
checksum_zip = "sha256:$hash"
files = @{
modified = $filteredModified
added = $filteredAdded
deleted = $deletedFilesOnly
}
directories_deleted = $deletedDirs
sql = $sqlQueries
changelog = $ChangelogEntry
}
$manifestJson = $manifest | ConvertTo-Json -Depth 4
$manifestPath = "$updatesDir/ver_${versionNumber}_manifest.json"
[System.IO.File]::WriteAllText($manifestPath, $manifestJson, $Utf8NoBom)
Write-Ok "Utworzono manifest: $manifestPath"
# --- 12. Legacy _sql.txt i _files.txt (okres przejsciowy) ---
if ($sqlQueries.Count -gt 0) {
$sqlPath = "$updatesDir/ver_${versionNumber}_sql.txt"
[System.IO.File]::WriteAllText($sqlPath, ($sqlQueries -join "`n"), $Utf8NoBom)
Write-Ok "Utworzono legacy SQL: $sqlPath"
}
if ($deletedFilesOnly.Count -gt 0 -or $deletedDirs.Count -gt 0) {
$filesContent = @()
foreach ($f in $deletedFilesOnly) { $filesContent += "F: ../$f" }
foreach ($d in $deletedDirs) { $filesContent += "D: ../$d" }
$filesPath = "$updatesDir/ver_${versionNumber}_files.txt"
[System.IO.File]::WriteAllText($filesPath, ($filesContent -join "`n"), $Utf8NoBom)
Write-Ok "Utworzono legacy files: $filesPath"
}
# --- 13. Aktualizacja versions.php ---
$versionsFile = "updates/versions.php"
if (Test-Path $versionsFile) {
$content = Get-Content $versionsFile -Raw
$content = $content -replace '\$current_ver\s*=\s*\d+;', "`$current_ver = $versionInt;"
[System.IO.File]::WriteAllText($versionsFile, $content, $Utf8NoBom)
Write-Ok "Zaktualizowano versions.php: `$current_ver = $versionInt"
}
# --- 14. Aktualizacja changelog-data.html ---
$changelogFile = "updates/changelog-data.html"
if (Test-Path $changelogFile) {
$dateStr = Get-Date -Format "dd.MM.yyyy"
$newEntry = "<b>ver. $versionNumber - $dateStr</b><br />`n$ChangelogEntry`n<hr>`n"
$changelogContent = [System.IO.File]::ReadAllText($changelogFile, $Utf8NoBom)
$changelogContent = $newEntry + $changelogContent
[System.IO.File]::WriteAllText($changelogFile, $changelogContent, $Utf8NoBom)
Write-Ok "Zaktualizowano changelog-data.html"
}
# --- 15. Cleanup ---
if (Test-Path $tempDir) {
Remove-Item -Recurse -Force $tempDir
}
# Usun pusty folder temp jesli nie ma juz w nim nic
if ((Test-Path "temp") -and ((Get-ChildItem "temp" -Force).Count -eq 0)) {
Remove-Item "temp" -Force
}
Write-Ok "Wyczyszczono pliki tymczasowe"
# --- Podsumowanie ---
Write-Host "`n=== Gotowe ===" -ForegroundColor Green
Write-Host " ZIP: $zipPath"
Write-Host " Manifest: $manifestPath"
Write-Host " Wersja: $versionNumber (int: $versionInt)"
Write-Host ""