#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, [switch]$SkipBuild, [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' $buildExit = 0 if ($SkipBuild) { Write-Host '' Write-Host 'сборка пропущена (-SkipBuild): публикую то, что уже лежит в out/' -ForegroundColor Yellow } else { 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 }