Найдено сверх задания и сверх аудита. Каждый прогон Release Pipeline завершался ошибкой — все пять последних, включая тег текущего релиза v0.1.3-b1. Причина та же, что у красного CI: шаг Release Gate падал на test_a37_isolation_guards и test_a41_clean_install. До публикации не доходил ни один прогон, релизы выкладывались мимо конвейера. Отсюда ловушка. release.yml собирает hermes-hub-<версия>.zip и update_manifest.json, а update_manager ищет строго HermesHubSetup.exe или hermes-hub-setup.sh. Настоящие релизы содержат установщики и checksums.txt, то есть собраны не этим конвейером. Пока тесты были красными, конвейер падал и ничего не публиковал; как только они позеленели, случайная защита исчезла: первый же тег опубликовал бы "latest" без установщиков, и любое обновление отвечало бы "В релизе не найден подходящий файл обновления для текущей платформы". Ловушка закрыта до публикации: release_gate.py --assets dist проверяет, что собранный набор содержит установщик и checksums.txt, и падает с названной причиной и подсказкой про installer/build_installer.*. После публикации добавлен шаг release_gate.py --publication-only — строгий режим, ради которого ворота и разделялись. Сборку установщиков в release.yml не переписывал: проверяется только настоящей публикацией по тегу, это решение владельца. Конвейер по-прежнему не доходит до публикации, но падает теперь с честной причиной вместо чужой. Отчёт перенесён в agents/done/ по конвенции репозитория. Тесты: 777 -> 778 passed, 2 skipped, 4 deselected. ruff check . чисто. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
94 lines
4.1 KiB
YAML
94 lines
4.1 KiB
YAML
name: Release Pipeline
|
||
|
||
on:
|
||
push:
|
||
tags:
|
||
- 'v*'
|
||
|
||
jobs:
|
||
build-and-release:
|
||
name: Build Release Package & Manifest
|
||
runs-on: windows-latest
|
||
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Set up Python 3.11
|
||
uses: actions/setup-python@v5
|
||
with:
|
||
python-version: '3.11'
|
||
|
||
- name: Install dependencies & dev tools
|
||
run: |
|
||
python -m pip install --upgrade pip
|
||
pip install -e ".[dev,web]"
|
||
|
||
- name: Run Release Gate Check
|
||
run: |
|
||
python scripts/release_gate.py
|
||
|
||
- name: Build Update Package & Manifest
|
||
shell: pwsh
|
||
run: |
|
||
$ver = "${{ github.ref_name }}".TrimStart("v")
|
||
$distDir = "dist"
|
||
New-Item -ItemType Directory -Force -Path $distDir
|
||
|
||
# Create zip archive of the app
|
||
$zipName = "hermes-hub-$ver.zip"
|
||
$zipPath = "$distDir/$zipName"
|
||
Compress-Archive -Path src, assets, config, launcher, pyproject.toml, README.md -DestinationPath $zipPath -Force
|
||
|
||
# Calculate SHA256
|
||
$hash = (Get-FileHash -Path $zipPath -Algorithm SHA256).Hash.ToLower()
|
||
|
||
# Generate Update Manifest
|
||
$manifest = @{
|
||
version = $ver
|
||
channel = "stable"
|
||
minimum_hermes_version = "0.20.0"
|
||
published_at = (Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ")
|
||
package_url = "https://github.com/ochenstarik-ui/hermes-hub/releases/download/${{ github.ref_name }}/$zipName"
|
||
sha256 = $hash
|
||
release_notes_url = "https://github.com/ochenstarik-ui/hermes-hub/releases/tag/${{ github.ref_name }}"
|
||
}
|
||
|
||
$manifest | ConvertTo-Json -Depth 5 | Out-File -FilePath "$distDir/update_manifest.json" -Encoding utf8
|
||
Write-Host "Generated update_manifest.json with SHA256: $hash"
|
||
|
||
# Набор проверяется ДО публикации.
|
||
#
|
||
# update_manager ищет в релизе строго HermesHubSetup.exe или
|
||
# hermes-hub-setup.sh, а шаг выше собирает только zip и манифест. Такой
|
||
# релиз становится "latest", и любая попытка обновиться отвечает «в
|
||
# релизе не найден подходящий файл обновления для текущей платформы».
|
||
#
|
||
# Раньше это не проявлялось лишь потому, что весь конвейер падал на шаге
|
||
# Release Gate — на тех же двух дефектах, что и CI; ни один его прогон не
|
||
# доходил до публикации, а релизы выкладывались мимо него. Как только
|
||
# тесты позеленели, случайная защита исчезла.
|
||
- name: Built assets must be installable by the updater
|
||
run: |
|
||
python scripts/release_gate.py --assets dist
|
||
|
||
- name: Publish GitHub Release
|
||
uses: softprops/action-gh-release@v2
|
||
with:
|
||
files: |
|
||
dist/hermes-hub-*.zip
|
||
dist/update_manifest.json
|
||
generate_release_notes: true
|
||
draft: false
|
||
prerelease: false
|
||
env:
|
||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
# Ворота публикации: проверяют опубликованный релиз, а не сборку.
|
||
# Релиз есть, ассеты есть, пакет скачан целиком, SHA-256 сошёлся с
|
||
# опубликованным checksums.txt. Здесь они блокируют: раньше эта проверка
|
||
# возвращала PASS при обрыве сети, при 404 на манифест и при 404 на
|
||
# пакет, то есть пропускала релиз при любом исходе.
|
||
- name: Publication Gate (published release must be verifiable)
|
||
run: |
|
||
python scripts/release_gate.py --publication-only
|