176 lines
7.6 KiB
PowerShell
176 lines
7.6 KiB
PowerShell
#Requires -Version 5.1
|
||
<#
|
||
.SYNOPSIS
|
||
Локальная сборка прошивок MeshCore под Windows с публикацией в Gitea.
|
||
|
||
.DESCRIPTION
|
||
Запускает ci/build-firmwares.sh (тот же путь сборки, что и в CI: build.sh, merge-bin,
|
||
uf2) через Git Bash, а готовые файлы из out/ при необходимости прикрепляет к релизу
|
||
в Gitea. Сам сервер при этом не нагружается — на него уходит только загрузка файлов.
|
||
|
||
Зачем: на VPS всего 1 CPU, полный набор прошивок собирается там часами. Локально —
|
||
быстрее, а результат удобно раздать через релиз Gitea.
|
||
|
||
.PARAMETER Targets
|
||
Список env через запятую. Пусто — набор устройств форка из ci/build-firmwares.sh.
|
||
|
||
.PARAMETER Match
|
||
Подстрока имени env: собрать все подходящие (например, promicro).
|
||
|
||
.PARAMETER Version
|
||
FIRMWARE_VERSION — попадает в имена файлов (по умолчанию local).
|
||
|
||
.PARAMETER Publish
|
||
Создать релиз в Gitea и прикрепить к нему файлы из out/.
|
||
|
||
.PARAMETER Tag
|
||
Тег для релиза (обязателен с -Publish). Если тега в репозитории нет — он будет создан
|
||
от текущего коммита.
|
||
|
||
.PARAMETER Public
|
||
Опубликовать релиз сразу. Без этого флага создаётся черновик.
|
||
|
||
.PARAMETER Token
|
||
Токен Gitea с правом write:repository. По умолчанию берётся из переменной GITEA_TOKEN.
|
||
|
||
.EXAMPLE
|
||
.\ci\build-local.ps1 -Match promicro -Version v1.0.0
|
||
|
||
.EXAMPLE
|
||
.\ci\build-local.ps1 -Version v1.0.0 -Publish -Tag companion-v1.0.0
|
||
#>
|
||
param(
|
||
[string]$Targets = '',
|
||
[string]$Match = '',
|
||
[string]$Version = 'local',
|
||
[switch]$Publish,
|
||
[string]$Tag = '',
|
||
[switch]$Public,
|
||
[string]$Token = $env:GITEA_TOKEN,
|
||
[string]$GiteaUrl = 'https://git.meshinfo.ru',
|
||
[string]$Repo = 'shade/MeshCore'
|
||
)
|
||
|
||
$ErrorActionPreference = 'Stop'
|
||
$root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||
Push-Location $root
|
||
|
||
try {
|
||
# --- ищем Git Bash -------------------------------------------------------
|
||
$bash = @(
|
||
"$env:ProgramFiles\Git\bin\bash.exe",
|
||
"${env:ProgramFiles(x86)}\Git\bin\bash.exe",
|
||
"$env:LOCALAPPDATA\Programs\Git\bin\bash.exe"
|
||
) | Where-Object { Test-Path $_ } | Select-Object -First 1
|
||
if (-not $bash) { $bash = (Get-Command bash -ErrorAction SilentlyContinue).Source }
|
||
if (-not $bash) { throw 'Git Bash не найден — установите Git for Windows' }
|
||
Write-Host "Git Bash: $bash"
|
||
|
||
# --- ищем рабочий python3 для build.sh ----------------------------------
|
||
# В Git Bash путь должен быть в unix-виде: C:\Tools\python.exe -> /c/Tools/python.exe
|
||
$pythonCandidates = @(
|
||
"$env:USERPROFILE\.platformio\penv\Scripts\python.exe",
|
||
'C:\Espressif\tools\python\python.exe'
|
||
)
|
||
$python = $pythonCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
|
||
if (-not $python) {
|
||
$cmd = Get-Command python -ErrorAction SilentlyContinue
|
||
if ($cmd) { $python = $cmd.Source }
|
||
}
|
||
if (-not $python) { throw 'Не найден python.exe (нужен для build.sh)' }
|
||
$pythonUnix = '/' + $python.Substring(0, 1).ToLower() + $python.Substring(2).Replace('\', '/')
|
||
Write-Host "python3 для build.sh: $pythonUnix"
|
||
|
||
# --- pio должен быть доступен и для bash ---------------------------------
|
||
$pioDir = Join-Path $env:USERPROFILE '.platformio\penv\Scripts'
|
||
if ((Test-Path (Join-Path $pioDir 'pio.exe')) -and ($env:PATH -notlike "*$pioDir*")) {
|
||
$env:PATH = "$pioDir;$env:PATH"
|
||
}
|
||
$pioCheck = & $bash -c 'command -v pio' 2>$null
|
||
if (-not $pioCheck) { throw 'PlatformIO (pio) не найден в PATH — установите PlatformIO Core' }
|
||
Write-Host "pio: $pioCheck"
|
||
|
||
# --- сборка --------------------------------------------------------------
|
||
$env:FIRMWARE_VERSION = $Version
|
||
$env:TARGETS = $Targets
|
||
$env:MATCH = $Match
|
||
$env:PYTHON3 = $pythonUnix
|
||
|
||
# out/ чистим, иначе в релиз попадут файлы прошлых сборок
|
||
$outDir = Join-Path $root 'out'
|
||
if (Test-Path $outDir) { Get-ChildItem $outDir -File | Remove-Item -Force }
|
||
|
||
Write-Host ''
|
||
Write-Host "=== сборка (версия $Version) ===" -ForegroundColor Cyan
|
||
& $bash 'ci/build-firmwares.sh'
|
||
$buildExit = $LASTEXITCODE
|
||
|
||
$files = @(Get-ChildItem $outDir -File -ErrorAction SilentlyContinue)
|
||
Write-Host ''
|
||
Write-Host "файлов в out/: $($files.Count)"
|
||
$files | ForEach-Object { ' {0} {1:N0} байт' -f $_.Name, $_.Length }
|
||
|
||
if ($buildExit -ne 0) { Write-Warning "часть env не собралась (код $buildExit)" }
|
||
|
||
# --- публикация релиза ---------------------------------------------------
|
||
if ($Publish) {
|
||
if (-not $Tag) { throw 'С -Publish нужно указать -Tag, например -Tag companion-v1.0.0' }
|
||
if (-not $Token) { throw 'Нужен токен Gitea: -Token <токен> или переменная окружения GITEA_TOKEN' }
|
||
if ($files.Count -eq 0) { throw 'В out/ нет файлов — публиковать нечего' }
|
||
|
||
$api = "$GiteaUrl/api/v1/repos/$Repo"
|
||
$headers = @{ Authorization = "token $Token"; 'Content-Type' = 'application/json' }
|
||
|
||
# тег создаём, если его ещё нет (на текущем коммите).
|
||
# В Gitea тег создаётся через POST /tags (у /git/refs нет метода POST).
|
||
$tagExists = $true
|
||
try { Invoke-RestMethod -Method Get -Uri "$api/tags/$Tag" -Headers $headers | Out-Null }
|
||
catch { $tagExists = $false }
|
||
if (-not $tagExists) {
|
||
$sha = (git -C $root rev-parse HEAD).Trim()
|
||
$body = @{ tag_name = $Tag; target = $sha } | ConvertTo-Json -Compress
|
||
Invoke-RestMethod -Method Post -Uri "$api/tags" -Headers $headers -Body $body | Out-Null
|
||
Write-Host "создан тег $Tag на коммите $($sha.Substring(0,8))"
|
||
}
|
||
else {
|
||
Write-Host "тег $Tag уже существует"
|
||
}
|
||
|
||
$draft = if ($Public) { 'false' } else { 'true' }
|
||
$releaseBody = @{
|
||
tag_name = $Tag
|
||
name = $Tag
|
||
draft = ($draft -eq 'true')
|
||
prerelease = $false
|
||
target_commitish = 'main'
|
||
} | ConvertTo-Json -Compress -Depth 3
|
||
|
||
try {
|
||
$release = Invoke-RestMethod -Method Post -Uri "$api/releases" -Headers $headers -Body $releaseBody
|
||
Write-Host "релиз #$($release.id) создан ($(if ($Public) { 'опубликован' } else { 'черновик' }))"
|
||
}
|
||
catch {
|
||
throw "Не удалось создать релиз: $($_.Exception.Message)"
|
||
}
|
||
|
||
foreach ($f in $files) {
|
||
& curl.exe -sS -X POST "$api/releases/$($release.id)/assets?name=$($f.Name)" `
|
||
-H "Authorization: token $Token" -F "attachment=@$($f.FullName)" | Out-Null
|
||
if ($LASTEXITCODE -ne 0) { Write-Warning "не загрузился: $($f.Name)" }
|
||
else { Write-Host " прикреплён $($f.Name)" }
|
||
}
|
||
|
||
Write-Host ''
|
||
Write-Host "Релиз: $GiteaUrl/$Repo/releases" -ForegroundColor Green
|
||
}
|
||
else {
|
||
Write-Host ''
|
||
Write-Host 'Файлы готовы в out/. Чтобы прикрепить их к релизу Gitea, добавьте -Publish -Tag <тег>' -ForegroundColor Yellow
|
||
}
|
||
|
||
exit $buildExit
|
||
}
|
||
finally {
|
||
Pop-Location
|
||
}
|