ci: drop requests dependency and use PowerShell for the Windows release upload
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 12m29s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 13m26s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 13m39s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 13m48s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m6s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 14m8s
Build Packages / build:windows:nocuda (push) Successful in 14m26s
Build Packages / build:windows:cuda (push) Successful in 17m26s
Build Packages / XDS test (durin plugin) (push) Successful in 7m20s
Build Packages / build:rpm (rocky8) (push) Successful in 11m40s
Build Packages / build:windows:nocuda (pull_request) Successful in 9m34s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m18s
Build Packages / Generate python client (push) Successful in 17s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 11m58s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 1m8s
Build Packages / build:rpm (rocky9) (push) Successful in 13m19s
Build Packages / DIALS test (push) Successful in 13m23s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m32s
Build Packages / XDS test (neggia plugin) (push) Successful in 6m16s
Build Packages / build:windows:cuda (pull_request) Successful in 16m40s
Build Packages / build:rpm (ubuntu2204_nocuda) (pull_request) Successful in 9m55s
Build Packages / build:rpm (rocky8_nocuda) (pull_request) Successful in 10m55s
Build Packages / build:rpm (rocky9_nocuda) (pull_request) Successful in 11m12s
Build Packages / build:rpm (ubuntu2404_nocuda) (pull_request) Successful in 9m35s
Build Packages / build:rpm (rocky8_sls9) (pull_request) Successful in 10m36s
Build Packages / build:rpm (ubuntu2204) (pull_request) Successful in 9m58s
Build Packages / build:rpm (rocky8) (pull_request) Successful in 11m15s
Build Packages / build:rpm (rocky9_sls9) (pull_request) Successful in 12m7s
Build Packages / build:rpm (rocky9) (pull_request) Successful in 11m42s
Build Packages / build:rpm (ubuntu2404) (pull_request) Successful in 10m21s
Build Packages / Generate python client (pull_request) Successful in 25s
Build Packages / Build documentation (pull_request) Successful in 57s
Build Packages / Create release (pull_request) Skipped
Build Packages / XDS test (neggia plugin) (pull_request) Successful in 6m12s
Build Packages / XDS test (durin plugin) (pull_request) Successful in 7m24s
Build Packages / XDS test (JFJoch plugin) (pull_request) Successful in 6m58s
Build Packages / DIALS test (pull_request) Successful in 10m41s
Build Packages / Unit tests (push) Successful in 1h11m21s
Build Packages / Unit tests (pull_request) Successful in 58m33s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 12m29s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 13m26s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 13m39s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 13m48s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m6s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 14m8s
Build Packages / build:windows:nocuda (push) Successful in 14m26s
Build Packages / build:windows:cuda (push) Successful in 17m26s
Build Packages / XDS test (durin plugin) (push) Successful in 7m20s
Build Packages / build:rpm (rocky8) (push) Successful in 11m40s
Build Packages / build:windows:nocuda (pull_request) Successful in 9m34s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m18s
Build Packages / Generate python client (push) Successful in 17s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 11m58s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 1m8s
Build Packages / build:rpm (rocky9) (push) Successful in 13m19s
Build Packages / DIALS test (push) Successful in 13m23s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m32s
Build Packages / XDS test (neggia plugin) (push) Successful in 6m16s
Build Packages / build:windows:cuda (pull_request) Successful in 16m40s
Build Packages / build:rpm (ubuntu2204_nocuda) (pull_request) Successful in 9m55s
Build Packages / build:rpm (rocky8_nocuda) (pull_request) Successful in 10m55s
Build Packages / build:rpm (rocky9_nocuda) (pull_request) Successful in 11m12s
Build Packages / build:rpm (ubuntu2404_nocuda) (pull_request) Successful in 9m35s
Build Packages / build:rpm (rocky8_sls9) (pull_request) Successful in 10m36s
Build Packages / build:rpm (ubuntu2204) (pull_request) Successful in 9m58s
Build Packages / build:rpm (rocky8) (pull_request) Successful in 11m15s
Build Packages / build:rpm (rocky9_sls9) (pull_request) Successful in 12m7s
Build Packages / build:rpm (rocky9) (pull_request) Successful in 11m42s
Build Packages / build:rpm (ubuntu2404) (pull_request) Successful in 10m21s
Build Packages / Generate python client (pull_request) Successful in 25s
Build Packages / Build documentation (pull_request) Successful in 57s
Build Packages / Create release (pull_request) Skipped
Build Packages / XDS test (neggia plugin) (pull_request) Successful in 6m12s
Build Packages / XDS test (durin plugin) (pull_request) Successful in 7m24s
Build Packages / XDS test (JFJoch plugin) (pull_request) Successful in 6m58s
Build Packages / DIALS test (pull_request) Successful in 10m41s
Build Packages / Unit tests (push) Successful in 1h11m21s
Build Packages / Unit tests (pull_request) Successful in 58m33s
The Windows viewer runner has Python but not the 'requests' package, and does not necessarily have bash. So: - rewrite gitea_upload_file.py to use only the Python stdlib (urllib), which works with a bare interpreter on both the Linux package runners and Windows; also drop the file's unused create_release() (gitea_create_release.py owns that); - run the Windows 'Upload installer to release' step in PowerShell (always present) instead of bash, globbing the NSIS .exe with Get-ChildItem. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -99,21 +99,17 @@ jobs:
|
||||
cpack
|
||||
- name: Upload installer to release
|
||||
if: github.ref_type == 'tag'
|
||||
shell: bash
|
||||
shell: powershell
|
||||
env:
|
||||
TOKEN: ${{ secrets.PIP_REPOSITORY_API_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
shopt -s nullglob
|
||||
# NSIS installer named jfjoch-<version>-win64-{cuda<major>|cpu}.exe (see CMakeLists.txt).
|
||||
files=(build/jfjoch-*-win64-*.exe)
|
||||
if [ ${#files[@]} -eq 0 ]; then
|
||||
echo "No Windows installer found in build/"
|
||||
exit 1
|
||||
fi
|
||||
for file in "${files[@]}"; do
|
||||
python gitea_upload_file.py "$file"
|
||||
done
|
||||
$files = Get-ChildItem -Path build -Filter 'jfjoch-*-win64-*.exe'
|
||||
if ($files.Count -eq 0) { throw 'No Windows installer found in build/' }
|
||||
foreach ($file in $files) {
|
||||
python gitea_upload_file.py $file.FullName
|
||||
if ($LASTEXITCODE -ne 0) { throw "Upload failed for $($file.Name)" }
|
||||
}
|
||||
build-rpm:
|
||||
name: build:rpm (${{ matrix.distro }})
|
||||
if: github.ref_type != 'workflow_dispatch'
|
||||
|
||||
+56
-74
@@ -1,15 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Uploads a file as an asset to the Gitea release for the tag in the VERSION file.
|
||||
# Uses only the standard library (no 'requests'), so it runs with a bare Python
|
||||
# interpreter on the Linux package runners and on the Windows viewer runner alike.
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
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/"
|
||||
gitea_api_url = "https://gitea.psi.ch/api/v1"
|
||||
repo_owner = "mx"
|
||||
repo_name = "jungfraujoch"
|
||||
|
||||
@@ -18,6 +21,7 @@ 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:
|
||||
@@ -26,57 +30,45 @@ def read_version():
|
||||
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
|
||||
}
|
||||
def _api_request(method: str, url: str, headers: dict, data: Optional[bytes] = None):
|
||||
req = urllib.request.Request(url, data=data, headers=headers, method=method)
|
||||
try:
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
return resp.status, resp.read()
|
||||
except urllib.error.HTTPError as e:
|
||||
return e.code, e.read()
|
||||
|
||||
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',
|
||||
}
|
||||
"""Fetch release information by tag name; exits on error."""
|
||||
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)
|
||||
headers = {'Authorization': f'token {gitea_token}'}
|
||||
status, body = _api_request('GET', url, headers)
|
||||
if status != 200:
|
||||
print(f"ERROR: Failed to fetch release {version}. Status code: {status}")
|
||||
print(body.decode(errors='replace'))
|
||||
sys.exit(1)
|
||||
return resp.json()
|
||||
return json.loads(body)
|
||||
|
||||
|
||||
def _multipart_body(fields: dict, file_field: str, file_name: str, file_bytes: bytes):
|
||||
"""Encode a multipart/form-data body; returns (body, content_type)."""
|
||||
boundary = uuid.uuid4().hex
|
||||
sep = f'--{boundary}'.encode()
|
||||
parts = []
|
||||
for name, value in fields.items():
|
||||
parts += [sep, f'Content-Disposition: form-data; name="{name}"'.encode(),
|
||||
b'', value.encode()]
|
||||
parts += [sep,
|
||||
f'Content-Disposition: form-data; name="{file_field}"; filename="{file_name}"'.encode(),
|
||||
b'Content-Type: application/octet-stream', b'', file_bytes]
|
||||
parts += [f'--{boundary}--'.encode(), b'']
|
||||
return b'\r\n'.join(parts), f'multipart/form-data; boundary={boundary}'
|
||||
|
||||
|
||||
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)
|
||||
"""
|
||||
"""Upload a file as an asset to the release identified by the given version tag."""
|
||||
if not os.path.isfile(file_path):
|
||||
print(f"ERROR: File not found: {file_path}")
|
||||
sys.exit(1)
|
||||
@@ -84,42 +76,32 @@ def upload_file_to_release(version: str, file_path: str, name: Optional[str] = N
|
||||
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')
|
||||
release_id = get_release_by_tag(version).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}
|
||||
fields = {'name': asset_name}
|
||||
if label:
|
||||
data['label'] = label
|
||||
|
||||
url = f'{gitea_api_url}/repos/{repo_owner}/{repo_name}/releases/{release_id}/assets'
|
||||
fields['label'] = label
|
||||
|
||||
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)
|
||||
body, content_type = _multipart_body(fields, 'attachment', asset_name, f.read())
|
||||
|
||||
if resp.status_code not in (201, 200):
|
||||
print(f"ERROR: Failed to upload asset. Status code: {resp.status_code}")
|
||||
print(resp.text)
|
||||
url = f'{gitea_api_url}/repos/{repo_owner}/{repo_name}/releases/{release_id}/assets'
|
||||
headers = {'Authorization': f'token {gitea_token}', 'Content-Type': content_type}
|
||||
status, resp_body = _api_request('POST', url, headers, body)
|
||||
if status not in (200, 201):
|
||||
print(f"ERROR: Failed to upload asset. Status code: {status}")
|
||||
print(resp_body.decode(errors='replace'))
|
||||
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}")
|
||||
asset = json.loads(resp_body)
|
||||
download_url = asset.get('browser_download_url') or asset.get('url')
|
||||
print(f"Uploaded asset '{asset_name}' to release {version}: {download_url}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
version = read_version()
|
||||
if len(sys.argv) != 2:
|
||||
exit(1)
|
||||
|
||||
upload_file_to_release(version, sys.argv[1])
|
||||
|
||||
upload_file_to_release(read_version(), sys.argv[1])
|
||||
|
||||
Reference in New Issue
Block a user