#!/usr/bin/env python3 """Build package, optionally publish to PyPI, and create Gitea release. Usage: GITEA_TOKEN= [PYPI_TOKEN=] python3 scripts/publish.py """ import os import subprocess import sys import click import requests from gitea_runner_manager.i18n import _ GITEA_API = "https://git.oblachno.oblachno.fyi/api/v1" def build_package() -> None: """Build the Python package using python -m build.""" result = subprocess.run( [sys.executable, "-m", "build"], capture_output=True, text=True, check=False, ) if result.returncode != 0: raise click.ClickException( _( "Oops! Package build failed:\n{stderr}", stderr=result.stderr.strip(), ) ) def publish_to_pypi(token: str) -> None: """Publish built packages to PyPI using twine.""" result = subprocess.run( [ sys.executable, "-m", "twine", "upload", "dist/*", "-u", "__token__", "-p", token, ], capture_output=True, text=True, check=False, ) if result.returncode != 0: raise click.ClickException( _( "Oops! PyPI publish failed:\n{stderr}", stderr=result.stderr.strip(), ) ) click.echo(_("Published to PyPI.")) def create_gitea_release(token: str, repo: str, tag: str) -> None: """Create a Gitea release for the given tag.""" url = f"{GITEA_API}/repos/{repo}/releases" headers = { "Authorization": f"token {token}", "Content-Type": "application/json", } payload = { "tag_name": tag, "name": tag, "body": f"Release {tag}\n\nSee CHANGELOG.md for details.", "draft": False, "prerelease": False, } response = requests.post(url, headers=headers, json=payload, timeout=30) response.raise_for_status() @click.command() @click.argument("tag") @click.argument("repo") def main(tag: str, repo: str) -> None: gitea_token = os.environ.get("GITEA_TOKEN", "") if not gitea_token: raise click.ClickException(_("ERROR: GITEA_TOKEN is not set.")) pypi_token = os.environ.get("PYPI_TOKEN", "") build_package() if pypi_token: publish_to_pypi(pypi_token) else: click.echo(_("PYPI_TOKEN not set — skipping PyPI publish. No worries, we'll just create the Gitea release.")) try: create_gitea_release(gitea_token, repo, tag) except requests.HTTPError as e: response = e.response status = response.status_code if response else 0 try: body = response.json() if response else {} message = body.get("message", str(e)) except Exception: message = str(e) raise click.ClickException( _( "Release creation failed with HTTP {status}: {message}", status=status, message=message, ) ) from None click.echo( _( "Nice! Gitea release {tag} created.", tag=tag, ) ) if __name__ == "__main__": # pragma: no cover main()