#!/usr/bin/env python3 """Build package, optionally publish to PyPI, and create Gitea release. Usage: GITEA_TOKEN= [PYPI_TOKEN=] python3 scripts/publish.py """ import argparse import os import subprocess import sys import requests 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: print("ERROR: Package build failed.") print(result.stderr) sys.exit(1) 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: print("ERROR: PyPI publish failed.") print(result.stderr) sys.exit(1) print("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() def main(args: list[str] | None = None) -> None: # pragma: no cover argv = args if args is not None else sys.argv parser = argparse.ArgumentParser(description="Build and publish release") parser.add_argument("tag", help="Git tag (e.g. v1.0.0)") parser.add_argument("repo", help="Repository full name (owner/repo)") parsed = parser.parse_args(argv[1:]) gitea_token = os.environ.get("GITEA_TOKEN", "") if not gitea_token: print("ERROR: GITEA_TOKEN is not set.", file=sys.stderr) sys.exit(1) pypi_token = os.environ.get("PYPI_TOKEN", "") build_package() if pypi_token: publish_to_pypi(pypi_token) else: print("PYPI_TOKEN not set — skipping PyPI publish.") create_gitea_release(gitea_token, parsed.repo, parsed.tag) print(f"Gitea release {parsed.tag} created.") if __name__ == "__main__": # pragma: no cover main()