- src/: прошивка встроенного отладчика BL616 — составное USB-устройство 1209:C0CA: DirtyJTAG v3 (WinUSB через MS OS 2.0) + CDC-ACM UART к FPGA B3/C3; UART до 20 Мбод на DMA, JTAG до 30 МГц через аппаратный SPI; - bin/: загрузчик Sipeed (0x0) и штатная прошивка 2025030317 для отката; - gui/: TangProgrammer.exe (C# WinForms, .NET Framework 4) — загрузка FPGA в SRAM и во флеш-память, копия и стирание флеш-памяти FPGA, прошивка моста; светлая и тёмная тема; - scripts/: setup, build, flash, build_gui, make_portable, а также make_release и publish_release для релизов Gitea; - fpga_test/, tests/: тестовые проекты Gowin (loopback, stream) и тесты UART на Python; - tools/openFPGALoader/: openFPGALoader 1.1.1 для Windows x64. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
4.2 KiB
PowerShell
92 lines
4.2 KiB
PowerShell
# Publish dist\release\v<version>\ (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 = '<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<version>" 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
|