132 lines
6.5 KiB
PowerShell
132 lines
6.5 KiB
PowerShell
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',
|
||
'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
|
||
}
|