247 lines
11 KiB
PowerShell
247 lines
11 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
Полный локальный релиз: сборка + архивы + тег + публикация в Gitea.
|
||
.DESCRIPTION
|
||
Вызывается из Makefile: make release VERSION=X.Y.Z GIT_TOKEN=xxx
|
||
.PARAMETER Version
|
||
Версия релиза (например, 2.0.0). Обязательный.
|
||
.PARAMETER Token
|
||
Gitea API-токен. Если не указан — только локальная сборка.
|
||
.PARAMETER AppName
|
||
Имя приложения (передаётся из Makefile).
|
||
.PARAMETER BuildDir
|
||
Директория сборки (передаётся из Makefile).
|
||
.PARAMETER GiteaUrl
|
||
URL Gitea-сервера.
|
||
.PARAMETER GiteaRepo
|
||
Репозиторий в формате owner/repo.
|
||
.PARAMETER GoVersion
|
||
Версия Go (для описания релиза).
|
||
#>
|
||
param(
|
||
[Parameter(Mandatory)][string]$Version,
|
||
[string]$Token,
|
||
[string]$AppName = "genaudiobookinfo",
|
||
[string]$BuildDir = "build",
|
||
[string]$GiteaUrl = "https://github.dfv24.com",
|
||
[string]$GiteaRepo = "fofanov.dmitry/GenAudioBookInfo",
|
||
[string]$GoVersion = "unknown"
|
||
)
|
||
|
||
$ErrorActionPreference = "Stop"
|
||
$tag = "v$Version"
|
||
|
||
# ── Валидация ─────────────────────────────────────────────────────────────────
|
||
|
||
if ($Version -eq 'dev' -or $Version -eq '') {
|
||
Write-Host '!!! VERSION не указана. Использование: make release VERSION=X.Y.Z' -ForegroundColor Red
|
||
exit 1
|
||
}
|
||
|
||
$dirty = git status --porcelain
|
||
if ($dirty) {
|
||
Write-Host '!!! Есть незакоммиченные изменения. Сначала сделайте git commit.' -ForegroundColor Red
|
||
git status --short
|
||
exit 1
|
||
}
|
||
|
||
# ── Начало ────────────────────────────────────────────────────────────────────
|
||
|
||
Write-Host ""
|
||
Write-Host "══════════════════════════════════════════════" -ForegroundColor Cyan
|
||
Write-Host " Создание релиза $tag" -ForegroundColor Cyan
|
||
Write-Host "══════════════════════════════════════════════" -ForegroundColor Cyan
|
||
Write-Host ""
|
||
|
||
# ── [1/6] Кросс-компиляция ───────────────────────────────────────────────────
|
||
|
||
Write-Host ">>> [1/6] Кросс-компиляция для всех платформ..." -ForegroundColor Yellow
|
||
|
||
$env:GOOS = ''
|
||
$env:GOARCH = ''
|
||
Remove-Item Env:GOARM, Env:GOMIPS -ErrorAction SilentlyContinue
|
||
|
||
$ErrorActionPreference = "Continue"
|
||
& make build-all VERSION=$Version
|
||
$buildExit = $LASTEXITCODE
|
||
$ErrorActionPreference = "Stop"
|
||
if ($buildExit -ne 0) {
|
||
Write-Host "!!! Ошибка компиляции." -ForegroundColor Red
|
||
exit 1
|
||
}
|
||
|
||
# ── [2/6] Создание архивов ────────────────────────────────────────────────────
|
||
|
||
Write-Host ""
|
||
Write-Host ">>> [2/6] Создание архивов..." -ForegroundColor Yellow
|
||
|
||
$archDir = Join-Path $BuildDir "archives"
|
||
New-Item -ItemType Directory -Force $archDir | Out-Null
|
||
|
||
Get-ChildItem $BuildDir -File | Where-Object { $_.Name -ne '.env' } | ForEach-Object {
|
||
if ($_.Name -match '\.exe$') {
|
||
$arcName = $_.BaseName + '.zip'
|
||
Write-Host " $($_.Name) -> $arcName"
|
||
Compress-Archive -Path $_.FullName -DestinationPath (Join-Path $archDir $arcName) -Force
|
||
}
|
||
elseif ($_.Name -match "^$([regex]::Escape($AppName))-") {
|
||
$arcName = $_.Name + '.tar.gz'
|
||
Write-Host " $($_.Name) -> $arcName"
|
||
tar -czf (Join-Path $archDir $arcName) -C $BuildDir $_.Name
|
||
}
|
||
}
|
||
|
||
# ── [3/6] SHA256 ──────────────────────────────────────────────────────────────
|
||
|
||
Write-Host ""
|
||
Write-Host ">>> [3/6] Генерация SHA256..." -ForegroundColor Yellow
|
||
|
||
$checksumFile = Join-Path $archDir "checksums-sha256.txt"
|
||
$lines = Get-ChildItem $archDir -File |
|
||
Where-Object { $_.Name -ne 'checksums-sha256.txt' } |
|
||
Get-FileHash -Algorithm SHA256 |
|
||
ForEach-Object { "$($_.Hash.ToLower()) $(Split-Path $_.Path -Leaf)" }
|
||
$lines | Out-File -Encoding UTF8 $checksumFile
|
||
Write-Host " checksums-sha256.txt создан"
|
||
|
||
# ── [4/6] Тег ─────────────────────────────────────────────────────────────────
|
||
|
||
Write-Host ""
|
||
Write-Host ">>> [4/6] Создание тега $tag..." -ForegroundColor Yellow
|
||
|
||
$existingTag = git tag -l $tag
|
||
if ($existingTag) {
|
||
Write-Host " Тег $tag уже существует, пропускаю создание" -ForegroundColor Gray
|
||
} else {
|
||
git tag -a $tag -m "Release $tag"
|
||
}
|
||
$ErrorActionPreference = "Continue"
|
||
git push origin $tag 2>&1 | Out-Null
|
||
git push origin master 2>&1 | Out-Null
|
||
$ErrorActionPreference = "Stop"
|
||
|
||
# ── Проверка токена ───────────────────────────────────────────────────────────
|
||
|
||
if (-not $Token) {
|
||
Write-Host ""
|
||
Write-Host "══════════════════════════════════════════════" -ForegroundColor Yellow
|
||
Write-Host " Локальная сборка завершена." -ForegroundColor Yellow
|
||
Write-Host " Для загрузки в Gitea укажите GIT_TOKEN:" -ForegroundColor Yellow
|
||
Write-Host " make release VERSION=$Version GIT_TOKEN=<токен>" -ForegroundColor Yellow
|
||
Write-Host " Архивы: $archDir\" -ForegroundColor Yellow
|
||
Write-Host "══════════════════════════════════════════════" -ForegroundColor Yellow
|
||
exit 0
|
||
}
|
||
|
||
# ── [5/6] Создание релиза в Gitea ────────────────────────────────────────────
|
||
|
||
Write-Host ""
|
||
Write-Host ">>> [5/6] Создание релиза в Gitea..." -ForegroundColor Yellow
|
||
|
||
$commit = git rev-parse HEAD
|
||
$date = Get-Date -Format 'dd.MM.yyyy HH:mm UTC'
|
||
$prevTag = ''
|
||
$ErrorActionPreference = "Continue"
|
||
try { $prevTag = git describe --tags --abbrev=0 "$tag^" 2>&1 | Where-Object { $_ -is [string] } } catch {}
|
||
$ErrorActionPreference = "Stop"
|
||
|
||
$rawLog = @()
|
||
if ($prevTag) {
|
||
$rawLog = git log --pretty=format:"%s" "$prevTag..$tag" --no-merges 2>$null
|
||
} else {
|
||
$rawLog = git log --pretty=format:"%s" --no-merges 2>$null | Select-Object -First 50
|
||
}
|
||
|
||
$features = @()
|
||
$fixes = @()
|
||
$refactor = @()
|
||
$other = @()
|
||
|
||
($rawLog -split "`n") | Where-Object { $_ } | ForEach-Object {
|
||
$low = $_.ToLower()
|
||
if ($low -match '^(функция|feat|feature|добавлен|реализован|новое)') { $features += "- $_" }
|
||
elseif ($low -match '^(исправлен|fix|bugfix|баг|ошибка)') { $fixes += "- $_" }
|
||
elseif ($low -match '^(рефакторинг|refactor|оптимизац|улучшен)') { $refactor += "- $_" }
|
||
else { $other += "- $_" }
|
||
}
|
||
|
||
# Формируем тело релиза
|
||
$body = "## GenAudioBookInfo $tag`n`n"
|
||
|
||
if (Test-Path 'RELEASE_NOTES.md') {
|
||
$body += (Get-Content 'RELEASE_NOTES.md' -Raw) + "`n`n"
|
||
}
|
||
if ($features.Count -gt 0) { $body += "### Новые возможности`n" + ($features -join "`n") + "`n`n" }
|
||
if ($fixes.Count -gt 0) { $body += "### Исправления`n" + ($fixes -join "`n") + "`n`n" }
|
||
if ($refactor.Count -gt 0) { $body += "### Рефакторинг`n" + ($refactor -join "`n") + "`n`n" }
|
||
if ($other.Count -gt 0) { $body += "### Прочие изменения`n" + ($other -join "`n") + "`n`n" }
|
||
|
||
$body += "---`n`n### Информация о сборке`n`n"
|
||
$body += "| Параметр | Значение |`n|---|---|`n"
|
||
$body += "| Коммит | ``$commit`` |`n"
|
||
$body += "| Дата | $date |`n"
|
||
$body += "| Go | $GoVersion |`n"
|
||
|
||
# API: создание релиза
|
||
$releaseData = @{
|
||
tag_name = $tag
|
||
target_commitish = $commit
|
||
name = "$AppName $tag"
|
||
body = $body
|
||
draft = $false
|
||
prerelease = $false
|
||
} | ConvertTo-Json -Compress -Depth 5
|
||
|
||
$headers = @{
|
||
Authorization = "token $Token"
|
||
'Content-Type' = 'application/json'
|
||
}
|
||
|
||
$releaseResp = Invoke-RestMethod -Method Post `
|
||
-Uri "$GiteaUrl/api/v1/repos/$GiteaRepo/releases" `
|
||
-Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($releaseData)) `
|
||
-ErrorAction Stop
|
||
|
||
$releaseId = $releaseResp.id
|
||
Write-Host " Релиз создан: ID=$releaseId"
|
||
|
||
# ── [6/6] Загрузка файлов ────────────────────────────────────────────────────
|
||
|
||
Write-Host ""
|
||
Write-Host ">>> [6/6] Загрузка файлов..." -ForegroundColor Yellow
|
||
|
||
$ok = 0
|
||
$fail = 0
|
||
|
||
Get-ChildItem $archDir -File | ForEach-Object {
|
||
$fname = $_.Name
|
||
$fsize = '{0:N1} MB' -f ($_.Length / 1MB)
|
||
Write-Host -NoNewline (" {0,-55} [{1,6}] " -f $fname, $fsize)
|
||
|
||
try {
|
||
$bytes = [System.IO.File]::ReadAllBytes($_.FullName)
|
||
$uploadHeaders = @{
|
||
Authorization = "token $Token"
|
||
'Content-Type' = 'application/octet-stream'
|
||
}
|
||
Invoke-RestMethod -Method Post `
|
||
-Uri "$GiteaUrl/api/v1/repos/$GiteaRepo/releases/$releaseId/assets?name=$fname" `
|
||
-Headers $uploadHeaders -Body $bytes -ErrorAction Stop | Out-Null
|
||
Write-Host "OK" -ForegroundColor Green
|
||
$ok++
|
||
} catch {
|
||
Write-Host "ОШИБКА: $_" -ForegroundColor Red
|
||
$fail++
|
||
}
|
||
}
|
||
|
||
# ── Итог ──────────────────────────────────────────────────────────────────────
|
||
|
||
Write-Host ""
|
||
Write-Host "══════════════════════════════════════════════" -ForegroundColor Green
|
||
Write-Host " Загружено: $ok | Ошибок: $fail" -ForegroundColor Green
|
||
Write-Host " Релиз: $GiteaUrl/$GiteaRepo/releases/tag/$tag" -ForegroundColor Green
|
||
Write-Host "══════════════════════════════════════════════" -ForegroundColor Green
|
||
|
||
if ($fail -gt 0) { exit 1 }
|