Files
SbLauncher/release.ps1
T
2026-10-10 14:58:04 +03:00

132 lines
6.5 KiB
PowerShell
Raw Permalink 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.
param(
[Parameter(Mandatory = $true)]
[ValidatePattern('^\d+\.\d+\.\d+$')]
[string]$Version,
# Только для проверки сборки из рабочей копии. Такой архив помечен dev.
[switch]$AllowDirty
)
$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $MyInvocation.MyCommand.Path
Push-Location $root
try {
$inside = & git rev-parse --is-inside-work-tree 2>$null
if ($LASTEXITCODE -ne 0 -or $inside -ne 'true') {
throw 'Запустите скрипт из Git-репозитория проекта.'
}
$commit = (& git rev-parse --short=12 HEAD).Trim()
if ($LASTEXITCODE -ne 0) { throw 'Не удалось определить Git-коммит.' }
$changes = @(& git status --porcelain=v1 --untracked-files=normal)
if ($LASTEXITCODE -ne 0) { throw 'Не удалось проверить состояние Git.' }
$dirty = $changes.Count -gt 0
if ($dirty -and -not $AllowDirty) {
throw 'Для релиза нужен чистый Git-коммит. Для пробной сборки используйте -AllowDirty.'
}
$tag = 'v' + $Version
$baseProfiles = Join-Path $root 'profiles.base.json'
if (-not (Test-Path -LiteralPath $baseProfiles)) { throw 'Нет каталога базовых серверов profiles.base.json.' }
if ((Get-Content -LiteralPath $baseProfiles -Raw) -match '"(?:private_key|local_address)"\s*:') {
throw 'Базовый каталог содержит персональные поля WireGuard.'
}
foreach ($runtimeFile in @('bin\sb.exe', 'doc\doc.srs')) {
if (-not (Test-Path -LiteralPath (Join-Path $root $runtimeFile))) { throw "Нет обязательного файла $runtimeFile." }
}
& git show-ref --verify --quiet ("refs/tags/" + $tag)
if ($LASTEXITCODE -eq 0) {
$tagCommit = (& git rev-list -n 1 $tag).Trim()
$headCommit = (& git rev-parse HEAD).Trim()
if ($tagCommit -ne $headCommit) {
throw "Тег $tag уже указывает на другой коммит. Выберите новую версию."
}
}
$dist = Join-Path $root 'dist'
New-Item -ItemType Directory -Path $dist -Force | Out-Null
$stressRoot = Join-Path $dist ('stress-' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $stressRoot | Out-Null
$previousStressRoot = $env:SB_STRESS_ROOT
$previousTemp = $env:TEMP
$previousTmp = $env:TMP
$env:SB_STRESS_ROOT = $stressRoot
$env:TEMP = $stressRoot
$env:TMP = $stressRoot
try {
foreach ($mode in @('staged', 'importtest', 'profiletest', 'updatetest', 'stress', 'themetest')) {
Write-Host "[*] build.cmd $mode"
& $env:ComSpec /d /c build.cmd $mode
if ($LASTEXITCODE -ne 0) { throw "Сборка или проверка $mode завершилась с ошибкой." }
}
}
finally {
$env:SB_STRESS_ROOT = $previousStressRoot
$env:TEMP = $previousTemp
$env:TMP = $previousTmp
$stressFull = [IO.Path]::GetFullPath($stressRoot)
$distFull = [IO.Path]::GetFullPath($dist).TrimEnd('\') + '\'
if ($stressFull.StartsWith($distFull, [StringComparison]::OrdinalIgnoreCase)) {
Remove-Item -LiteralPath $stressFull -Recurse -Force
}
}
$exe = Join-Path $root 'SbLauncher.updated.exe'
$builtVersion = [Reflection.AssemblyName]::GetAssemblyName($exe).Version.ToString(3)
if ($builtVersion -ne $Version) {
throw "Версия сборки $builtVersion не совпадает с $Version. Обновите Version.cs."
}
$suffix = if ($dirty) { "-dev-$commit-$([DateTime]::UtcNow.ToString('yyyyMMddHHmmss'))" } else { '' }
$baseName = "SbLauncher-v$Version-win-x64$suffix"
$archive = Join-Path $dist ($baseName + '.zip')
$checksum = $archive + '.sha256'
if ((Test-Path -LiteralPath $archive) -or (Test-Path -LiteralPath $checksum)) {
throw "Файл $baseName уже существует в dist. Удалите его вручную или выберите новую версию."
}
$stage = Join-Path $dist ('stage-' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $stage | Out-Null
try {
Copy-Item -LiteralPath $exe -Destination (Join-Path $stage 'SbLauncher.exe')
foreach ($name in @('Ui.xaml', 'README.md', 'CHANGELOG.md', 'HANDOFF.md',
'profiles.base.json', 'profiles.example.json', 'local.example.json')) {
Copy-Item -LiteralPath (Join-Path $root $name) -Destination $stage
}
foreach ($runtimeDir in @('bin', 'doc')) {
New-Item -ItemType Directory -Path (Join-Path $stage $runtimeDir) | Out-Null
}
Copy-Item -LiteralPath (Join-Path $root 'bin\sb.exe') -Destination (Join-Path $stage 'bin\sb.exe')
Copy-Item -LiteralPath (Join-Path $root 'doc\doc.srs') -Destination (Join-Path $stage 'doc\doc.srs')
$templates = Join-Path $stage 'templates'
New-Item -ItemType Directory -Path $templates | Out-Null
foreach ($name in @('wg.json', 'direct.json', 'wgonly.json')) {
Copy-Item -LiteralPath (Join-Path (Join-Path $root 'templates') $name) -Destination $templates
}
$preview = Join-Path $stage 'preview'
New-Item -ItemType Directory -Path $preview | Out-Null
foreach ($name in @('glass-light.png', 'glass-dark.png')) {
Copy-Item -LiteralPath (Join-Path (Join-Path $root 'preview') $name) -Destination $preview
}
@("Version: $tag", "Commit: $commit", "Build: win-x64") |
Set-Content -LiteralPath (Join-Path $stage 'VERSION.txt') -Encoding UTF8
Compress-Archive -Path (Join-Path $stage '*') -DestinationPath $archive -CompressionLevel Optimal
}
finally {
$stageFull = [IO.Path]::GetFullPath($stage)
$distFull = [IO.Path]::GetFullPath($dist).TrimEnd('\') + '\'
if ($stageFull.StartsWith($distFull, [StringComparison]::OrdinalIgnoreCase)) {
Remove-Item -LiteralPath $stageFull -Recurse -Force
}
}
$hash = (Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash.ToLowerInvariant()
"$hash $($baseName).zip" | Set-Content -LiteralPath $checksum -Encoding ASCII
Write-Host "[+] $archive"
Write-Host "[+] $checksum"
if ($dirty) { Write-Warning 'Это пробная сборка из изменённой рабочей копии. Не публикуйте её как релиз.' }
}
finally {
Pop-Location
}