From 32b6f1c8a715b36426c2916e2b96e0732b0070b2 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 30 Sep 2025 13:40:29 +0200 Subject: [PATCH] Gitea: Try create release --- .gitea/workflows/build_and_test.yml | 14 +++- gitea_create_release.py | 117 ++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 gitea_create_release.py diff --git a/.gitea/workflows/build_and_test.yml b/.gitea/workflows/build_and_test.yml index 0b079c1b..744d1705 100644 --- a/.gitea/workflows/build_and_test.yml +++ b/.gitea/workflows/build_and_test.yml @@ -138,7 +138,19 @@ jobs: run: | twine upload -u __token__ -p ${{ secrets.CI_PYPI_TOKEN }} --skip-existing dist/* twine upload -u __token__ -p ${{ secrets.PIP_REPOSITORY_API_TOKEN }} --repository-url https://gitea.psi.ch/api/packages/mx/pypi dist/* - + create-release: + name: Create release + runs-on: jfjoch_rocky8 + # if: github.ref_type == 'tag' + steps: + - uses: actions/checkout@v4 + - name: Create release + env: + GITEA_TOKEN: ${{ secrets.PIP_REPOSITORY_API_TOKEN }} + shell: bash + run: | + git lfs pull + python3 gitea_create_release.py documentation: name: Build documentation runs-on: jfjoch_rocky8 diff --git a/gitea_create_release.py b/gitea_create_release.py new file mode 100644 index 00000000..1033aec2 --- /dev/null +++ b/gitea_create_release.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 + +import os +import requests +import sys + +gitea_api_url = "https://gitea.psi.ch/api/" +repo_owner = "mx" +repo_name = "jungfraujoch" + +gitea_token = os.getenv('GITEA_TOKEN') +if gitea_token is None: + print("ERROR: Required environment variables not set") + sys.exit(1) + +def read_version(): + try: + with open('VERSION', 'r') as f: + return f.readline().strip() + except FileNotFoundError: + print("ERROR: VERSION file not found") + sys.exit(1) + +def create_release(version): + headers = { + 'Authorization': f'token {gitea_token}', + 'Content-Type': 'application/json', + } + + data = { + 'tag_name': version, + 'name': f'Release {version}', + 'draft': False, + 'prerelease': '-rc.' in version or '-alpha.' in version or '-beta.' in version + } + + url = f'{gitea_api_url}/repos/{repo_owner}/{repo_name}/releases' + + response = requests.post(url, headers=headers, json=data) + if response.status_code != 201: + print(f"ERROR: Failed to create release. Status code: {response.status_code}") + print(response.text) + sys.exit(1) + + release = response.json() + print(f"Successfully created release {version}") + return release + +def get_release_by_tag(version: str): + """ + Fetch release information by tag name. + Returns the release object (dict) or exits on error. + """ + headers = { + 'Authorization': f'token {gitea_token}', + 'Content-Type': 'application/json', + } + url = f'{gitea_api_url}/repos/{repo_owner}/{repo_name}/releases/tags/{version}' + resp = requests.get(url, headers=headers) + if resp.status_code != 200: + print(f"ERROR: Failed to fetch release {version}. Status code: {resp.status_code}") + print(resp.text) + sys.exit(1) + return resp.json() + +def upload_file_to_release(version: str, file_path: str, name: str | None = None, label: str | None = None): + """ + Upload a file as an asset to the release identified by the given version tag. + + :param version: Tag name of the release (e.g., '1.2.3' or '1.2.3-rc.1') + :param file_path: Local file path to upload + :param name: Optional asset name to display in release (defaults to filename) + :param label: Optional asset label (display name) + """ + if not os.path.isfile(file_path): + print(f"ERROR: File not found: {file_path}") + sys.exit(1) + + # Ensure the release exists and get its ID + release = get_release_by_tag(version) + release_id = release.get('id') + if release_id is None: + print("ERROR: Release ID not found in response") + sys.exit(1) + + headers = { + 'Authorization': f'token {gitea_token}', + } + + asset_name = name if name else os.path.basename(file_path) + data = {'name': asset_name} + if label: + data['label'] = label + + url = f'{gitea_api_url}/repos/{repo_owner}/{repo_name}/releases/{release_id}/assets' + + with open(file_path, 'rb') as f: + files = { + 'attachment': (asset_name, f, 'application/octet-stream'), + } + resp = requests.post(url, headers=headers, data=data, files=files) + + if resp.status_code not in (201, 200): + print(f"ERROR: Failed to upload asset. Status code: {resp.status_code}") + print(resp.text) + sys.exit(1) + + asset = resp.json() + browser_download_url = asset.get('browser_download_url') or asset.get('browser_url') or asset.get('url') + print(f"Uploaded asset '{asset_name}' to release {version}: {browser_download_url}") + +if __name__ == '__main__': + version = read_version() + release = create_release(version) + + upload_file_to_release(version, 'fpga/images/jfjoch_fpga_pcie_8x10g.mcs.gz', 'jfjoch_fpga_pcie_8x10g.mcs.gz', '8x10G FPGA image') + upload_file_to_release(version, 'fpga/images/jfjoch_fpga_pcie_100g.mcs.gz', 'jfjoch_fpga_pcie_100g.mcs.gz', '100G FPGA image')