GRM-20: feat: replace inline workflow scripts with tested Python modules
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build package, optionally publish to PyPI, and create Gitea release.
|
||||
|
||||
Usage:
|
||||
GITEA_TOKEN=<token> [PYPI_TOKEN=<token>] python3 scripts/publish.py <tag> <repo>
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user