zapret2-youtube-discord/scripts/publish_forgejo_release.py
loop-uh 7d5aec1bc7
All checks were successful
Проверка восстановленного репозитория / validate (push) Successful in 4s
Выпуск Zapret2 для Windows / release (push) Successful in 7s
Восстановить полный Zapret2 и перенести выпуск в Forgejo
2026-08-07 17:10:02 +03:00

116 lines
3.9 KiB
Python
Raw Permalink 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.

#!/usr/bin/env python3
"""Создаёт неизменяемый релиз Forgejo и загружает собранные файлы."""
from __future__ import annotations
import json
import mimetypes
import os
import sys
import urllib.error
import urllib.parse
import urllib.request
from pathlib import Path
def required_env(name: str) -> str:
value = os.environ.get(name, "").strip()
if not value:
raise RuntimeError(f"не задана переменная окружения {name}")
return value
def request_json(
url: str,
token: str,
*,
method: str = "GET",
payload: dict[str, object] | None = None,
) -> dict[str, object]:
data = None if payload is None else json.dumps(payload).encode("utf-8")
headers = {
"Accept": "application/json",
"Authorization": f"token {token}",
"User-Agent": "zapret2-forgejo-release",
}
if data is not None:
headers["Content-Type"] = "application/json"
request = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(request, timeout=60) as response:
return json.load(response)
def upload_asset(url: str, token: str, path: Path) -> None:
content_type = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
request = urllib.request.Request(
f"{url}?{urllib.parse.urlencode({'name': path.name})}",
data=path.read_bytes(),
headers={
"Accept": "application/json",
"Authorization": f"token {token}",
"Content-Type": content_type,
"User-Agent": "zapret2-forgejo-release",
},
method="POST",
)
with urllib.request.urlopen(request, timeout=300) as response:
result = json.load(response)
print(f"Загружен {path.name}: {result.get('browser_download_url', '')}")
def main() -> int:
if len(sys.argv) < 2:
print(f"Использование: {sys.argv[0]} ФАЙЛ...", file=sys.stderr)
return 2
token = required_env("FORGEJO_TOKEN")
api_url = required_env("FORGEJO_API_URL").rstrip("/")
repository = required_env("FORGEJO_REPOSITORY")
tag = required_env("RELEASE_TAG")
assets = [Path(argument).resolve() for argument in sys.argv[1:]]
for asset in assets:
if not asset.is_file():
raise RuntimeError(f"файл релиза не найден: {asset}")
release_url = f"{api_url}/repos/{repository}/releases"
prerelease = "-" in tag
release = request_json(
release_url,
token,
method="POST",
payload={
"body": (
"Восстановленная автономная сборка Zapret2 для YouTube и Discord.\n\n"
"В релиз входят архив 7z, самораспаковывающийся EXE и SHA256SUMS.txt "
"для проверки целостности."
),
"draft": False,
"name": f"Zapret2 YouTube Discord {tag}",
"prerelease": prerelease,
"tag_name": tag,
"target_commitish": tag,
},
)
release_id = release.get("id")
if not isinstance(release_id, int):
raise RuntimeError("Forgejo не вернул числовой идентификатор релиза")
asset_url = f"{release_url}/{release_id}/assets"
for asset in assets:
upload_asset(asset_url, token, asset)
print(f"Релиз опубликован: {release.get('html_url', '')}")
return 0
if __name__ == "__main__":
try:
sys.exit(main())
except urllib.error.HTTPError as exc:
body = exc.read().decode("utf-8", errors="replace")
print(f"Forgejo API вернул HTTP {exc.code}: {body}", file=sys.stderr)
sys.exit(1)
except (OSError, RuntimeError, ValueError) as exc:
print(f"Ошибка публикации: {exc}", file=sys.stderr)
sys.exit(1)