Gitea: Create release pipeline

This commit is contained in:
2025-09-30 13:40:29 +02:00
parent 48227f51c3
commit d5d87e865a
3 changed files with 292 additions and 2 deletions
+45 -2
View File
@@ -8,10 +8,17 @@ on:
- '**'
pull_request:
workflow_dispatch:
inputs:
create_release:
type: boolean
description: 'Create release'
required: false
default: false
jobs:
build-rpm:
name: build:rpm (${{ matrix.distro }})
if: github.ref_type != 'workflow_dispatch'
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
@@ -88,8 +95,19 @@ jobs:
fi
for file in "${files[@]}"; do
echo "Uploading $file -> ${{ matrix.upload_url }}"
curl --fail --user __token__:"$TOKEN" --upload-file "$file" "${{ matrix.upload_url }}"
curl --fail --user __token__:"$TOKEN" --upload-file "$file" "${{ matrix.upload_url }}"
python gitea_upload_file.py
done
if [ "${{ matrix.distro }}" = "rocky8_nocuda" ]; then
for file in jfjoch-viewer*.rpm; do
python gitea_upload_file.py "$file"
done
elif [ "${{ matrix.distro }}" = "ubuntu2204_nocuda" ]; then
for file in jfjoch*viewer*.deb; do
python gitea_upload_file.py "$file"
done
fi
python-client:
name: Generate python client
runs-on: jfjoch_rocky8
@@ -103,7 +121,6 @@ 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/*
documentation:
name: Build documentation
runs-on: jfjoch_rocky8
@@ -133,6 +150,7 @@ jobs:
unit-tests:
name: Unit tests
runs-on: jfjoch_rocky8
if: github.ref_type != 'tag' && github.ref_type != 'workflow_dispatch'
container:
image: gitea.psi.ch/leonarski_f/jfjoch_rocky8:2509
options: --gpus all
@@ -158,3 +176,28 @@ jobs:
run: |
cd build/tools
./jfjoch_hdf5_test ../../tests/test_data/compression_benchmark.h5
create-release:
name: Create release
runs-on: jfjoch_rocky8
if: github.event_name == 'workflow_dispatch' && (github.event.inputs.create_release == 'true' || github.event.inputs.create_release == true)
steps:
- uses: actions/checkout@v4
with:
persist-credentials: 'true' # Optional; should be the default
- name: Configure auth and fetch LFS
shell: bash
env:
GITEA_TOKEN: ${{ secrets.PIP_REPOSITORY_API_TOKEN }}
run: |
git lfs install --local
AUTH=$(git config --local http.${{ github.server_url }}/.extraheader)
git config --local --unset http.${{ github.server_url }}/.extraheader
git config --local http.${{ github.server_url }}/${{ github.repository }}.git/info/lfs/objects/batch.extraheader "$AUTH"
git lfs pull
- name: Create release
env:
GITEA_TOKEN: ${{ secrets.PIP_REPOSITORY_API_TOKEN }}
shell: bash
run: |
python3 gitea_create_release.py
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env python3
import os
import sys
from typing import Optional
try:
import requests
except ModuleNotFoundError:
print("ERROR: Python 'requests' package is required. Please install it (e.g., pip install requests).")
sys.exit(1)
gitea_api_url = "https://gitea.psi.ch/api/v1/"
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: Optional[str] = None, label: Optional[str] = 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')
+125
View File
@@ -0,0 +1,125 @@
#!/usr/bin/env python3
import os
import sys
from typing import Optional
try:
import requests
except ModuleNotFoundError:
print("ERROR: Python 'requests' package is required. Please install it (e.g., pip install requests).")
sys.exit(1)
gitea_api_url = "https://gitea.psi.ch/api/v1/"
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: Optional[str] = None, label: Optional[str] = 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)
asset_name = name if name else os.path.basename(file_path)
print(f"Uploading file '{file_path}' to release {version} as {asset_name}")
# 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}',
}
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()
if len(sys.argv) != 2:
exit(1)
upload_file_to_release(version, sys.argv[1])