docs(changelog): add v0.1.1.3 download and SHA256 links; add release automation scripts (upload/prune/manage/checksums)

This commit is contained in:
mbusc
2025-08-28 17:05:06 +02:00
parent a741d3b969
commit eecbc47f5f
7 changed files with 330 additions and 0 deletions

View File

@ -0,0 +1,30 @@
param(
[Parameter(Mandatory=$true)][string]$OutDir
)
$ErrorActionPreference = 'Stop'
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
$items = @(
@{ Path = 'build/Release/privatebinapi.dll'; Optional = $false }
@{ Path = 'build/Release/privatebinapi.lib'; Optional = $true }
@{ Path = 'build/Release/privatebinapi.pdb'; Optional = $true }
@{ Path = 'build/example/Release/example.exe'; Optional = $true }
)
foreach ($it in $items) {
$p = Resolve-Path -LiteralPath $it.Path -ErrorAction SilentlyContinue
if ($null -ne $p) {
Copy-Item -LiteralPath $p.Path -Destination $OutDir -Force
Write-Host ("Collected: " + [IO.Path]::GetFileName($p.Path))
} elseif (-not $it.Optional) {
throw "Required artifact not found: $($it.Path)"
} else {
Write-Host ("Skip missing optional: " + $it.Path)
}
}
Get-ChildItem -LiteralPath $OutDir -File | Format-Table Name,Length -AutoSize

35
scripts/gen_checksums.ps1 Normal file
View File

@ -0,0 +1,35 @@
param(
[Parameter(Mandatory=$true)][string]$ZipPath,
[Parameter(Mandatory=$true)][string]$BinDir
)
$ErrorActionPreference = 'Stop'
if (-not (Test-Path -LiteralPath $ZipPath)) {
throw "ZIP not found: $ZipPath"
}
if (-not (Test-Path -LiteralPath $BinDir)) {
throw "BinDir not found: $BinDir"
}
function Write-ChecksumFile {
param(
[Parameter(Mandatory=$true)][string]$Path
)
$hash = (Get-FileHash -Algorithm SHA256 -LiteralPath $Path).Hash.ToLower()
$outfile = "$Path.sha256"
$line = "$hash $([System.IO.Path]::GetFileName($Path))"
Set-Content -Path $outfile -NoNewline -Encoding ASCII -Value $line
Write-Host "Wrote $outfile"
}
# ZIP checksum
Write-ChecksumFile -Path $ZipPath
# Binaries checksums
Get-ChildItem -LiteralPath $BinDir -File | ForEach-Object {
Write-ChecksumFile -Path $_.FullName
}

43
scripts/gitea_upload.ps1 Normal file
View File

@ -0,0 +1,43 @@
param(
[Parameter(Mandatory=$true)][string]$Server,
[Parameter(Mandatory=$true)][string]$Owner,
[Parameter(Mandatory=$true)][string]$Repo,
[Parameter(Mandatory=$true)][string]$Token,
[Parameter(Mandatory=$true)][string]$ZipPath
)
$ErrorActionPreference = 'Stop'
if (-not (Test-Path -LiteralPath $ZipPath)) {
throw "ZIP not found: $ZipPath"
}
$headers = @{ Authorization = "token $Token" }
$latestUrl = "$Server/api/v1/repos/$Owner/$Repo/releases/latest"
$latest = Invoke-RestMethod -Headers $headers -Method GET -Uri $latestUrl
if (-not $latest -or -not $latest.id) {
throw "Failed to get latest release from $latestUrl"
}
$rid = [string]$latest.id
$name = [System.IO.Path]::GetFileName($ZipPath)
$escapedName = [System.Uri]::EscapeDataString($name)
$uploadUrl = "$Server/api/v1/repos/$Owner/$Repo/releases/$rid/assets?name=$escapedName"
Write-Host "Latest release id: $rid"
Write-Host "Uploading $name to $uploadUrl"
# Use Invoke-WebRequest multipart form upload
$form = @{ attachment = Get-Item -LiteralPath $ZipPath }
$resp = Invoke-WebRequest -Headers $headers -Method Post -Uri $uploadUrl -Form $form
if ($resp.StatusCode -ge 200 -and $resp.StatusCode -lt 300) {
Write-Host "Upload successful (HTTP $($resp.StatusCode))"
} else {
Write-Host "Upload failed (HTTP $($resp.StatusCode))" -ForegroundColor Red
if ($resp.Content) { Write-Host $resp.Content }
exit 1
}

View File

@ -0,0 +1,45 @@
param(
[Parameter(Mandatory=$true)][string]$Server,
[Parameter(Mandatory=$true)][string]$Owner,
[Parameter(Mandatory=$true)][string]$Repo,
[Parameter(Mandatory=$true)][string]$Token,
[Parameter(Mandatory=$true)][string]$Directory
)
$ErrorActionPreference = 'Stop'
if (-not (Test-Path -LiteralPath $Directory)) {
throw "Directory not found: $Directory"
}
$headers = @{ Authorization = "token $Token" }
$latestUrl = "$Server/api/v1/repos/$Owner/$Repo/releases/latest"
$latest = Invoke-RestMethod -Headers $headers -Method GET -Uri $latestUrl
if (-not $latest -or -not $latest.id) {
throw "Failed to get latest release from $latestUrl"
}
$rid = [string]$latest.id
Write-Host "Latest release id: $rid"
$files = Get-ChildItem -LiteralPath $Directory -Recurse -File
if (-not $files) {
Write-Host "No files to upload in $Directory"
exit 0
}
foreach ($f in $files) {
$name = $f.Name
$escapedName = [System.Uri]::EscapeDataString($name)
$uploadUrl = "$Server/api/v1/repos/$Owner/$Repo/releases/$rid/assets?name=$escapedName"
Write-Host "Uploading $name ..."
try {
$resp = Invoke-WebRequest -Headers $headers -Method Post -Uri $uploadUrl -Form @{ attachment = $f }
Write-Host " OK ($($resp.StatusCode))"
}
catch {
Write-Host " FAIL: $name -> $($_.Exception.Message)" -ForegroundColor Red
}
}

View File

@ -0,0 +1,89 @@
param(
[Parameter(Mandatory=$true)][string]$Server,
[Parameter(Mandatory=$true)][string]$Owner,
[Parameter(Mandatory=$true)][string]$Repo,
[Parameter(Mandatory=$true)][string]$Token
)
$ErrorActionPreference = 'Stop'
$headers = @{ Authorization = "token $Token" }
# Get latest release
$latest = Invoke-RestMethod -Headers $headers -Method GET -Uri "$Server/api/v1/repos/$Owner/$Repo/releases/latest"
if (-not $latest -or -not $latest.id) {
throw "Failed to get latest release"
}
$rid = [string]$latest.id
Write-Host "Operating on release id: $rid"
# Load full release including attachments/assets list
$release = Invoke-RestMethod -Headers $headers -Method GET -Uri "$Server/api/v1/repos/$Owner/$Repo/releases/$rid"
$assets = $release.assets
if (-not $assets) { $assets = $release.attachments }
if ($assets) {
$groups = $assets | Group-Object -Property name
foreach ($g in $groups) {
$sorted = $g.Group | Sort-Object -Property id -Descending
if ($sorted.Count -gt 1) {
$keep = $sorted[0]
foreach ($extra in $sorted[1..($sorted.Count-1)]) {
if ($null -ne $extra -and $extra.id -ne $keep.id) {
$delUrl = "$Server/api/v1/repos/$Owner/$Repo/releases/assets/$($extra.id)"
try {
Invoke-RestMethod -Headers $headers -Method DELETE -Uri $delUrl | Out-Null
Write-Host ("Deleted duplicate asset: " + $extra.name + " (id=" + $extra.id + ")")
} catch {
Write-Host ("Failed to delete asset id=" + $extra.id + ": " + $_.Exception.Message) -ForegroundColor Red
}
}
}
}
}
} else {
Write-Host 'No assets found on release.'
}
# Compose release notes with known checksums if they exist locally
$zipShaPath = (Resolve-Path 'dist\lib-privatebin-v0.1.1.3-windows-x64.zip.sha256' -ErrorAction SilentlyContinue)
$dllShaPath = (Resolve-Path 'dist\windows_bin\privatebinapi.dll.sha256' -ErrorAction SilentlyContinue)
$libShaPath = (Resolve-Path 'dist\windows_bin\privatebinapi.lib.sha256' -ErrorAction SilentlyContinue)
$exeShaPath = (Resolve-Path 'dist\windows_bin\example.exe.sha256' -ErrorAction SilentlyContinue)
$lines = @('# Downloadable artifacts', '')
$lines += ("- [lib-privatebin-v0.1.1.3-windows-x64.zip]($Server/$Owner/$Repo/releases/download/$tag/lib-privatebin-v0.1.1.3-windows-x64.zip)")
$lines += ("- [privatebinapi.dll]($Server/$Owner/$Repo/releases/download/$tag/privatebinapi.dll)")
$lines += ("- [privatebinapi.lib]($Server/$Owner/$Repo/releases/download/$tag/privatebinapi.lib)")
$lines += ("- [example.exe]($Server/$Owner/$Repo/releases/download/$tag/example.exe)")
$lines += ''
$lines += '# SHA256 checksums'
if ($zipShaPath) { $lines += ("- [lib-privatebin-v0.1.1.3-windows-x64.zip.sha256]($Server/$Owner/$Repo/releases/download/$tag/lib-privatebin-v0.1.1.3-windows-x64.zip.sha256)") }
if ($dllShaPath) { $lines += ("- [privatebinapi.dll.sha256]($Server/$Owner/$Repo/releases/download/$tag/privatebinapi.dll.sha256)") }
if ($libShaPath) { $lines += ("- [privatebinapi.lib.sha256]($Server/$Owner/$Repo/releases/download/$tag/privatebinapi.lib.sha256)") }
if ($exeShaPath) { $lines += ("- [example.exe.sha256]($Server/$Owner/$Repo/releases/download/$tag/example.exe.sha256)") }
$lines += ''
$lines += '# Changes'
try {
$changelog = Get-Content -Raw -LiteralPath 'CHANGELOG.md'
$sections = $changelog -split "\r?\n## "
$section = $sections | Where-Object { $_ -like 'v0.1.1.3*' } | Select-Object -First 1
if ($section) {
$secLines = $section -split "\r?\n"
if ($secLines[0] -like 'v0.1.1.3*') { $secLines[0] = 'v0.1.1.3' }
$lines += $secLines
} else {
$lines += 'See CHANGELOG.md'
}
} catch {
$lines += 'See CHANGELOG.md'
}
$bodyText = ($lines -join "`n")
$payload = @{ body = $bodyText } | ConvertTo-Json -Depth 3
Invoke-RestMethod -Headers (@{ Authorization = ("token " + $Token); 'Content-Type' = 'application/json' }) -Method PATCH -Uri "$Server/api/v1/repos/$Owner/$Repo/releases/$rid" -Body $payload | Out-Null
Write-Host 'Release notes updated.'

View File

@ -0,0 +1,76 @@
param(
[Parameter(Mandatory=$true)][string]$Server,
[Parameter(Mandatory=$true)][string]$Owner,
[Parameter(Mandatory=$true)][string]$Repo,
[Parameter(Mandatory=$true)][string]$Token
)
$ErrorActionPreference = 'Stop'
$headers = @{ Authorization = "token $Token" }
$latest = Invoke-RestMethod -Headers $headers -Method GET -Uri "$Server/api/v1/repos/$Owner/$Repo/releases/latest"
if (-not $latest -or -not $latest.id) { throw 'Failed to get latest release' }
$rid = [string]$latest.id
$tag = $latest.tag_name
Write-Host "Pruning assets on release id=$rid (tag=$tag)"
$release = Invoke-RestMethod -Headers $headers -Method GET -Uri "$Server/api/v1/repos/$Owner/$Repo/releases/$rid"
$assets = $release.assets
if (-not $assets) { $assets = $release.attachments }
# Allowed asset names
$allowed = @(
'lib-privatebin-v0.1.1.3-windows-x64.zip',
'lib-privatebin-v0.1.1.3-windows-x64.zip.sha256',
'privatebinapi.dll','privatebinapi.dll.sha256',
'privatebinapi.lib','privatebinapi.lib.sha256',
'example.exe','example.exe.sha256'
)
if ($assets) {
foreach ($a in $assets) {
if ($allowed -notcontains $a.name) {
$delUrl = "$Server/api/v1/repos/$Owner/$Repo/releases/assets/$($a.id)"
try {
Invoke-RestMethod -Headers $headers -Method DELETE -Uri $delUrl | Out-Null
Write-Host ("Deleted: " + $a.name)
} catch {
Write-Host ("Skip delete (" + $a.name + "): " + $_.Exception.Message) -ForegroundColor Yellow
}
}
}
} else {
Write-Host 'No assets found.'
}
# Re-fetch assets after prune
$release = Invoke-RestMethod -Headers $headers -Method GET -Uri "$Server/api/v1/repos/$Owner/$Repo/releases/$rid"
$assets = $release.assets; if (-not $assets) { $assets = $release.attachments }
# Build markdown with links
$lines = @('# Downloadable artifacts', '')
foreach ($name in $allowed) {
$a = $assets | Where-Object { $_.name -eq $name } | Select-Object -First 1
if ($a) {
# Prefer deterministic download URL pattern
$url = "$Server/$Owner/$Repo/releases/download/$tag/$name"
$lines += ("- [$name]($url)")
}
}
$lines += ''
$lines += '# SHA256 checksums'
foreach ($name in $allowed | Where-Object { $_.EndsWith('.sha256') }) {
$a = $assets | Where-Object { $_.name -eq $name } | Select-Object -First 1
if ($a) {
$url = "$Server/$Owner/$Repo/releases/download/$tag/$name"
$lines += ("- [$name]($url)")
}
}
$bodyText = ($lines -join "`n")
$payload = @{ body = $bodyText } | ConvertTo-Json -Depth 3
Invoke-RestMethod -Headers (@{ Authorization = ("token " + $Token); 'Content-Type' = 'application/json' }) -Method PATCH -Uri "$Server/api/v1/repos/$Owner/$Repo/releases/$rid" -Body $payload | Out-Null
Write-Host 'Release notes updated with links.'