# Publish dist\release\v\ (made by make_release.ps1) as a Gitea # release: the release text is the version's section of CHANGELOG.md. The tag # has to be pushed already. Re-running uploads only the files that are missing. # # Needs a Gitea access token with the write:repository scope # (Settings -> Applications -> Generate New Token): # # $env:GITEA_TOKEN = '' # .\scripts\publish_release.ps1 version from src\sys.h # .\scripts\publish_release.ps1 -Version 1.0.1 param( [string]$Version, [string]$Token = $env:GITEA_TOKEN, [string]$Remote = 'origin' ) $ErrorActionPreference = 'Stop' $root = Split-Path $PSScriptRoot -Parent if (-not $Version) { $m = Select-String -Path (Join-Path $root 'src\sys.h') -Pattern '#define\s+FW_VERSION_STR\s+"([^"]+)"' if (-not $m) { throw 'FW_VERSION_STR not found in src\sys.h' } $Version = $m.Matches[0].Groups[1].Value } $Version = $Version.TrimStart('v') $tag = 'v' + $Version $dir = Join-Path $root "dist\release\$tag" if (-not (Test-Path $dir)) { throw "$dir not found: run scripts\make_release.ps1 first" } if (-not $Token) { throw 'no token: set $env:GITEA_TOKEN (Gitea: Settings -> Applications -> Generate New Token, scope write:repository)' } # http://server/owner/repo.git -> http://server/api/v1/repos/owner/repo $url = (& git -C $root remote get-url $Remote).Trim() if ($url -notmatch '^(https?://[^/]+)/(.+?)(\.git)?/?$') { throw "not an http(s) remote: $url" } $api = "$($Matches[1])/api/v1/repos/$($Matches[2])" # the release text: the lines under "## v" up to the next "## " $notes = New-Object System.Collections.Generic.List[string] $inside = $false foreach ($line in [IO.File]::ReadAllLines((Join-Path $root 'CHANGELOG.md'), [Text.Encoding]::UTF8)) { if ($line -match '^## ') { if ($inside) { break } $inside = $line -match "^## v?$([regex]::Escape($Version))\b" } elseif ($inside) { $notes.Add($line) } } if (-not $inside) { throw "no '## $tag' section in CHANGELOG.md" } $body = ($notes -join "`n").Trim() Add-Type -AssemblyName System.Net.Http $http = New-Object System.Net.Http.HttpClient $http.Timeout = [TimeSpan]::FromMinutes(10) $http.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue 'token', $Token function Invoke-Gitea([string]$Method, [string]$Path, [System.Net.Http.HttpContent]$Content) { $req = New-Object System.Net.Http.HttpRequestMessage ([System.Net.Http.HttpMethod]::new($Method)), ($api + $Path) if ($Content) { $req.Content = $Content } $resp = $http.SendAsync($req).GetAwaiter().GetResult() $text = $resp.Content.ReadAsStringAsync().GetAwaiter().GetResult() $code = [int]$resp.StatusCode if ($code -ge 400 -and $code -ne 404) { throw "$Method $Path -> $code $text" } return [pscustomobject]@{ Code = $code; Json = $(if ($text) { $text | ConvertFrom-Json } else { $null }) } } if ((Invoke-Gitea GET "/tags/$tag").Code -eq 404) { throw "tag $tag is not on the server: git tag -a $tag -m $tag; git push $Remote $tag" } $r = Invoke-Gitea GET "/releases/tags/$tag" if ($r.Code -eq 404) { $json = ConvertTo-Json @{ tag_name = $tag; name = $tag; body = $body; draft = $false; prerelease = $false } $r = Invoke-Gitea POST '/releases' (New-Object System.Net.Http.StringContent $json, ([Text.Encoding]::UTF8), 'application/json') Write-Host "Created release $tag" } else { Write-Host "Release $tag exists, adding missing files" } $release = $r.Json $have = @($release.assets | ForEach-Object { $_.name }) foreach ($f in Get-ChildItem $dir -File | Sort-Object Name) { if ($have -contains $f.Name) { Write-Host " = $($f.Name) (already there)" continue } $file = [System.Net.Http.ByteArrayContent]::new([IO.File]::ReadAllBytes($f.FullName)) $file.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::new('application/octet-stream') $form = New-Object System.Net.Http.MultipartFormDataContent $form.Add($file, 'attachment', $f.Name) Invoke-Gitea POST "/releases/$($release.id)/assets?name=$([Uri]::EscapeDataString($f.Name))" $form | Out-Null Write-Host (" + {0} ({1:N0} KB)" -f $f.Name, ($f.Length / 1KB)) } Write-Host "OK: $($release.html_url)" -ForegroundColor Green