diff --git a/.github/scripts/winget-restore-fields.ps1 b/.github/scripts/winget-restore-fields.ps1 new file mode 100644 index 0000000..cfab9ce --- /dev/null +++ b/.github/scripts/winget-restore-fields.ps1 @@ -0,0 +1,49 @@ +# Возвращает в winget-манифест рукописные поля, которые Komac (winget-releaser) +# теряет при пересборке installer-манифеста из portable-exe. История: MinimumOSVersion +# уехал в 0.7.0 и 0.8.0 — без него валидатор winget-pkgs режет PR («Inconsistencies +# detected … Missing property MinimumOSVersion»). +# +# Работает по ветке ФОРКА (Oksion/winget-pkgs), а не по PR: ветку Komac создаёт с +# детерминированным префиксом Oksion.XiControl-<версия>-, коммит в неё сам обновляет +# открытый PR, и не нужен Search API (он лагает первые минуты после создания PR). +# Идемпотентен: поле уже на месте → выходит без изменений, шаг можно перезапускать. +# +# Локальный запуск (нужен gh с правами на форк): ./winget-restore-fields.ps1 -Tag v0.8.0 +param([Parameter(Mandatory)][string]$Tag) +$ErrorActionPreference = 'Stop' + +$version = $Tag -replace '^v', '' +$fork = 'Oksion/winget-pkgs' +$prefix = "Oksion.XiControl-$version-" +$path = "manifests/o/Oksion/XiControl/$version/Oksion.XiControl.installer.yaml" + +# ветка появляется, когда winget-releaser отработал; в CI шаг идёт следом, +# но даём API время на согласованность +$branch = $null +for ($i = 0; $i -lt 12 -and -not $branch; $i++) { + if ($i) { Start-Sleep -Seconds 10 } + $branch = gh api "repos/$fork/branches?per_page=100" --paginate --jq '.[].name' | + Where-Object { $_.StartsWith($prefix) } | Select-Object -First 1 +} +if (-not $branch) { throw "Ветка $prefix* в $fork не найдена — winget-releaser не отработал?" } +Write-Host "Ветка PR: $branch" + +$file = gh api "repos/$fork/contents/${path}?ref=$branch" | ConvertFrom-Json +$text = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($file.content)) + +if ($text -match '(?m)^MinimumOSVersion:') { + Write-Host 'MinimumOSVersion уже на месте — Komac починили? Патч не нужен.' + exit 0 +} + +# вставляем по порядку полей эталона (reference/winget/): после Platform, перед InstallerType +$lines = [System.Collections.Generic.List[string]]($text -split "`r?`n") +$idx = $lines.FindIndex({ param($l) $l -match '^InstallerType:' }) +if ($idx -lt 0) { throw "В $path не нашлась строка InstallerType — формат манифеста изменился, нужен глаз." } +$lines.Insert($idx, 'MinimumOSVersion: 10.0.0.0') + +$b64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(($lines -join "`n"))) +gh api -X PUT "repos/$fork/contents/$path" ` + -f message="Restore MinimumOSVersion dropped by Komac (portable manifest)" ` + -f content=$b64 -f sha=$($file.sha) -f branch=$branch | Out-Null +Write-Host "MinimumOSVersion возвращён в $path (ветка $branch); валидация PR перезапустится сама." diff --git a/.github/workflows/winget.yml b/.github/workflows/winget.yml index cc31d84..0ea84ef 100644 --- a/.github/workflows/winget.yml +++ b/.github/workflows/winget.yml @@ -23,6 +23,8 @@ jobs: env: HAS_TOKEN: ${{ secrets.WINGET_TOKEN != '' }} steps: + - uses: actions/checkout@v7 # ради .github/scripts (winget-releaser чекаут не нужен) + if: env.HAS_TOKEN == 'true' - name: Publish to winget if: env.HAS_TOKEN == 'true' uses: vedantmgoyal9/winget-releaser@v2 @@ -32,6 +34,15 @@ jobs: # тег: из ввода при ручном запуске, иначе из события release release-tag: ${{ inputs.tag || github.event.release.tag_name }} token: ${{ secrets.WINGET_TOKEN }} + # Komac пересобирает installer-манифест из exe и теряет рукописные поля — + # MinimumOSVersion уезжал в 0.7.0 и 0.8.0, валидатор winget без него режет PR. + # Возвращаем поля прямо в ветку форка (PR обновится сам); скрипт идемпотентен. + - name: Restore hand-written manifest fields + if: env.HAS_TOKEN == 'true' + shell: pwsh + env: + GH_TOKEN: ${{ secrets.WINGET_TOKEN }} + run: ./.github/scripts/winget-restore-fields.ps1 -Tag '${{ inputs.tag || github.event.release.tag_name }}' - name: No token — skip if: env.HAS_TOKEN != 'true' run: echo "Секрет WINGET_TOKEN не задан — публикация в winget пропущена." diff --git a/CLAUDE.md b/CLAUDE.md index 190fbd4..ff619bc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -225,6 +225,9 @@ WMI-событий). `Program.cs`: single-instance mutex → DI-контейне файл с живым железом — впиши его в исключения, иначе гейт покраснеет на ровном месте. - Локальная сборка помечается версией `0.0.0-dev` (дев-дефолт в `XiControl.csproj`, суффикс виден в AboutTab); реальную версию подставляет CI из тега: `publish -p:Version=X.Y.Z`. +- winget-PR Komac пересобирает из exe и теряет рукописные поля (`MinimumOSVersion` — в 0.7.0 и 0.8.0); + `winget.yml` возвращает их сам шагом `.github/scripts/winget-restore-fields.ps1` (правит ветку + форка, идемпотентен). После релиза всё равно свериться с эталоном `reference/winget/<версия>/`. ## Ограничения среды