Files
GenAudioBookInfo/.gitea/workflows/release.yml
Dmitriy Fofanov 41fb62f62e Добавлены страницы вики для GenAudioBookInfo: Home, Installation, Makefile, OpenRouter, Output Structure, TorrAPI и Sidebar.
Создана структура документации, описывающая функциональность, установку, использование CLI, архитектуру и интеграции с TorrAPI и OpenRouter.
Добавлены примеры конфигурации и метаданных, а также описание структуры выходных данных.
2026-02-23 13:19:39 +03:00

363 lines
20 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ══════════════════════════════════════════════════════════════════════════════
# CI/CD Pipeline: Сборка и публикация релиза GenAudioBookInfo
# ══════════════════════════════════════════════════════════════════════════════
#
# ЗАПУСК ТОЛЬКО ЧЕРЕЗ make — два способа:
#
# 1. make release-tag VERSION=2.1.0
# Создаёт аннотированный git-тег v2.1.0 и пушит его в origin.
# Workflow запускается автоматически по событию push.tags.
#
# 2. make ci-release VERSION=2.1.0 GITEA_TOKEN=<токен>
# Вызывает Gitea API (workflow_dispatch) — запускает вручную
# без создания тега. Удобно для тестирования пайплайна.
#
# ──────────────────────────────────────────────────────────────────────────────
# ЭТАПЫ ПАЙПЛАЙНА:
#
# [Этап 1] quality — Статический анализ (go vet) + Unit-тесты
# Блокирует следующие этапы при ошибке.
#
# [Этап 2] build — Определение версии, кросс-компиляция 15 бинарников
# для Linux / macOS / Windows / FreeBSD / OpenBSD /
# NetBSD / MIPS / RISC-V, упаковка в архивы,
# генерация SHA256 контрольных сумм.
#
# [Этап 3] publish — Создание Gitea Release через API,
# загрузка всех архивов и checksums-sha256.txt.
#
# ──────────────────────────────────────────────────────────────────────────────
# НЕОБХОДИМАЯ НАСТРОЙКА:
#
# В настройках репозитория Gitea → Settings → Secrets добавить:
# GITEA_TOKEN — токен с правами write:repository и write:release
# (обычно автоматически инжектируется runner'ом)
#
# ══════════════════════════════════════════════════════════════════════════════
name: "Release CI/CD"
on:
# ── Способ 1: запуск через make ci-release ────────────────────────────────
workflow_dispatch:
inputs:
version:
description: "Версия релиза (например: 2.1.0). Без префикса 'v'."
required: false
default: ""
prerelease:
description: "Отметить как пре-релиз (alpha/beta)?"
required: false
default: "false"
# ── Способ 2: запуск через make release-tag ───────────────────────────────
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]*"
# ──────────────────────────────────────────────────────────────────────────────
# Глобальные переменные окружения (доступны во всех jobs)
# ──────────────────────────────────────────────────────────────────────────────
env:
GO_VERSION: "1.24" # Версия Go для сборки
APP_NAME: genaudiobookinfo
BUILD_DIR: build
# ══════════════════════════════════════════════════════════════════════════════
jobs:
# ────────────────────────────────────────────────────────────────────────────
# ЭТАП 1: Проверка качества кода
# ────────────────────────────────────────────────────────────────────────────
quality:
name: "Этап 1 — Качество кода"
runs-on: ubuntu-latest
steps:
- name: "Получение исходного кода"
uses: actions/checkout@v4
- name: "Установка Go ${{ env.GO_VERSION }}"
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: "Загрузка зависимостей (go mod download)"
run: make deps
- name: "Статический анализ (go vet)"
# Проверяет корректность кода без запуска: подозрительные
# конструкции, неправильные форматные строки, ошибки типов.
run: make vet
- name: "Unit-тесты (go test)"
# -count=1 — отключает кеш результатов (всегда свежий прогон)
# -timeout 5m — предел времени выполнения тестов
run: go test ./... -count=1 -timeout 5m
# ────────────────────────────────────────────────────────────────────────────
# ЭТАП 2: Кросс-компиляция и подготовка артефактов
# ────────────────────────────────────────────────────────────────────────────
build:
name: "Этап 2 — Кросс-компиляция"
runs-on: ubuntu-latest
needs: quality # Запускается только после успешного прохождения Этапа 1
outputs:
# Версия и тег передаются в Этап 3 через outputs
version: ${{ steps.ver.outputs.version }}
tag: ${{ steps.ver.outputs.tag }}
steps:
- name: "Получение исходного кода (полная история для тегов)"
uses: actions/checkout@v4
with:
fetch-depth: 0 # Нужна полная история для git describe
- name: "Установка Go ${{ env.GO_VERSION }}"
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
# ── Определение версии ────────────────────────────────────────────────
# Приоритет: git-тег > ручной ввод (inputs.version) > значение в Makefile
- name: "Определение версии релиза"
id: ver
run: |
if [ "${{ github.event_name }}" = "push" ]; then
# Запуск через make release-tag: версия берётся из имени тега
TAG="${{ github.ref_name }}" # например: v2.0.0
VER="${TAG#v}" # например: 2.0.0
elif [ -n "${{ inputs.version }}" ]; then
# Запуск через make ci-release с явной версией
VER="${{ inputs.version }}"
TAG="v${VER}"
else
# Версия не задана — берём из Makefile (строка VERSION := X.Y.Z)
VER=$(grep '^VERSION' Makefile | head -1 | sed 's/.*:=\s*//' | tr -d ' ')
TAG="v${VER}"
fi
echo "version=${VER}" >> "$GITHUB_OUTPUT"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "──────────────────────────────────"
echo " Версия: ${VER}"
echo " Git-тег: ${TAG}"
echo " Коммит: ${{ github.sha }}"
echo "──────────────────────────────────"
- name: "Загрузка зависимостей"
run: make deps
# ── Кросс-компиляция ─────────────────────────────────────────────────
# make build-all собирает 15 бинарников через GOOS/GOARCH
# VERSION перезаписывает значение из Makefile (инжектируется в ldflags)
- name: "Кросс-компиляция для всех платформ"
run: |
make build-all VERSION=${{ steps.ver.outputs.version }}
echo ""
echo "Собранные бинарники:"
ls -lh ${{ env.BUILD_DIR }}/
# ── Упаковка в архивы ─────────────────────────────────────────────────
# Windows → ZIP (стандарт для Windows-пользователей)
# Всё остальное → tar.gz (стандарт для Unix-систем)
- name: "Создание архивов (zip / tar.gz)"
run: |
cd ${{ env.BUILD_DIR }}
mkdir -p archives
echo "=== Windows → ZIP ==="
for f in *-windows-*.exe; do
[ -f "$f" ] || continue
ARCNAME="${f%.exe}.zip"
echo " ${f} → archives/${ARCNAME}"
zip "archives/${ARCNAME}" "$f"
done
echo "=== Unix → TAR.GZ ==="
for f in \
*-linux-* \
*-darwin-* \
*-freebsd-* \
*-openbsd-* \
*-netbsd-*; do
[[ "$f" == *.exe ]] && continue
[ -f "$f" ] || continue
ARCNAME="${f}.tar.gz"
echo " ${f} → archives/${ARCNAME}"
tar -czf "archives/${ARCNAME}" "$f"
done
echo ""
echo "Готовые архивы:"
ls -lh archives/
# ── Контрольные суммы ─────────────────────────────────────────────────
# SHA256 для каждого архива — пользователи могут проверить целостность
- name: "Генерация контрольных сумм SHA256"
run: |
cd ${{ env.BUILD_DIR }}/archives
sha256sum * | tee checksums-sha256.txt
echo ""
echo "checksums-sha256.txt создан ($(wc -l < checksums-sha256.txt) файлов)"
# ── Передача артефактов в Этап 3 ─────────────────────────────────────
- name: "Сохранение артефактов"
uses: actions/upload-artifact@v4
with:
name: release-assets-${{ steps.ver.outputs.tag }}
path: ${{ env.BUILD_DIR }}/archives/
retention-days: 5
if-no-files-found: error # Ошибка если архивы не созданы
# ────────────────────────────────────────────────────────────────────────────
# ЭТАП 3: Публикация релиза в Gitea
# ────────────────────────────────────────────────────────────────────────────
publish:
name: "Этап 3 — Публикация релиза"
runs-on: ubuntu-latest
needs: build # Запускается только после успешного Этапа 2
env:
VERSION: ${{ needs.build.outputs.version }}
TAG: ${{ needs.build.outputs.tag }}
PRERELEASE: ${{ inputs.prerelease || 'false' }}
steps:
- name: "Скачивание артефактов из Этапа 2"
uses: actions/download-artifact@v4
with:
name: release-assets-${{ needs.build.outputs.tag }}
path: ./artifacts
- name: "Список артефактов для публикации"
run: |
echo "Артефакты ($(ls ./artifacts | wc -l) файлов):"
ls -lh ./artifacts/
# ── Создание Gitea Release и загрузка файлов ─────────────────────────
# Используется Gitea REST API v1:
# POST /api/v1/repos/{owner}/{repo}/releases — создать релиз
# POST /api/v1/repos/{owner}/{repo}/releases/{id}/assets — загрузить файл
- name: "Создание релиза в Gitea и загрузка файлов"
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
GITEA_URL="${{ github.server_url }}"
REPO="${{ github.repository }}"
COMMIT="${{ github.sha }}"
DATE=$(date -u '+%Y-%m-%d %H:%M UTC')
echo "──────────────────────────────────────────────"
echo " Сервер: ${GITEA_URL}"
echo " Репо: ${REPO}"
echo " Версия: ${TAG}"
echo " Коммит: ${COMMIT}"
echo "──────────────────────────────────────────────"
# ── Тело описания релиза (Markdown) ────────────────────────────
RELEASE_BODY="## GenAudioBookInfo ${TAG}
### Платформы
| ОС | Архитектура | Файл |
|---|---|---|
| Windows | amd64 (64-бит) | \`genaudiobookinfo-windows-amd64.zip\` |
| Windows | 386 (32-бит) | \`genaudiobookinfo-windows-386.zip\` |
| Windows | arm64 | \`genaudiobookinfo-windows-arm64.zip\` |
| Linux | amd64 | \`genaudiobookinfo-linux-amd64.tar.gz\` |
| Linux | arm64 | \`genaudiobookinfo-linux-arm64.tar.gz\` |
| Linux | armv7 | \`genaudiobookinfo-linux-armv7.tar.gz\` |
| Linux | 386 | \`genaudiobookinfo-linux-386.tar.gz\` |
| Linux | MIPS (big-endian) | \`genaudiobookinfo-linux-mips.tar.gz\` |
| Linux | MIPS (little-endian) | \`genaudiobookinfo-linux-mipsle.tar.gz\` |
| Linux | RISC-V 64 | \`genaudiobookinfo-linux-riscv64.tar.gz\` |
| macOS | amd64 (Intel) | \`genaudiobookinfo-darwin-amd64.tar.gz\` |
| macOS | arm64 (Apple Silicon) | \`genaudiobookinfo-darwin-arm64.tar.gz\` |
| FreeBSD | amd64 | \`genaudiobookinfo-freebsd-amd64.tar.gz\` |
| FreeBSD | arm64 | \`genaudiobookinfo-freebsd-arm64.tar.gz\` |
| OpenBSD | amd64 | \`genaudiobookinfo-openbsd-amd64.tar.gz\` |
| NetBSD | amd64 | \`genaudiobookinfo-netbsd-amd64.tar.gz\` |
> Контрольные суммы файлов: \`checksums-sha256.txt\`
### Сборка
- **Коммит:** \`${COMMIT}\`
- **Дата:** ${DATE}
- **Go:** ${{ env.GO_VERSION }}"
# ── Создать релиз через API ─────────────────────────────────────
echo ""
echo "Создаём релиз ${TAG}..."
RELEASE_JSON=$(curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases" \
-d "{
\"tag_name\": \"${TAG}\",
\"target_commitish\": \"${COMMIT}\",
\"name\": \"${{ env.APP_NAME }} ${TAG}\",
\"body\": $(echo "$RELEASE_BODY" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))'),
\"draft\": false,
\"prerelease\": ${PRERELEASE}
}")
RELEASE_ID=$(echo "$RELEASE_JSON" | \
python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('id',''))" 2>/dev/null || true)
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "None" ]; then
echo "ОШИБКА: не удалось создать релиз!"
echo "Ответ API:"
echo "$RELEASE_JSON" | python3 -m json.tool 2>/dev/null || echo "$RELEASE_JSON"
exit 1
fi
echo "Релиз создан: ID=${RELEASE_ID}"
# ── Загрузить каждый артефакт ────────────────────────────────────
echo ""
echo "Загружаем артефакты..."
UPLOAD_OK=0
UPLOAD_FAIL=0
for FILE in ./artifacts/*; do
[ -f "$FILE" ] || continue
FILENAME=$(basename "$FILE")
FILESIZE=$(du -sh "$FILE" | cut -f1)
printf " %-55s [%5s] " "${FILENAME}" "${FILESIZE}"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/octet-stream" \
--data-binary @"${FILE}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${FILENAME}")
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
echo "OK (HTTP ${HTTP_CODE})"
UPLOAD_OK=$((UPLOAD_OK + 1))
else
echo "ОШИБКА (HTTP ${HTTP_CODE})"
UPLOAD_FAIL=$((UPLOAD_FAIL + 1))
fi
done
# ── Итог ─────────────────────────────────────────────────────────
echo ""
echo "══════════════════════════════════════════════"
echo " Загружено успешно: ${UPLOAD_OK}"
echo " Ошибок: ${UPLOAD_FAIL}"
echo " Релиз: ${GITEA_URL}/${REPO}/releases/tag/${TAG}"
echo "══════════════════════════════════════════════"
if [ "$UPLOAD_FAIL" -gt 0 ]; then
echo "Часть файлов не удалось загрузить!"
exit 1
fi