feat: add build and upload scripts for Forgejo PyPI, update version management

This commit is contained in:
claudi 2026-03-03 13:44:58 +01:00
parent 462c8aeac9
commit 64ea445ec3
12 changed files with 1288 additions and 0 deletions

3
.gitignore vendored
View file

@ -25,6 +25,9 @@ dmypy.json
# Environment files
.env
# PyPI credentials
.pypirc
# pytest
.pytest_cache/
.coverage

25
.pypirc.example Normal file
View file

@ -0,0 +1,25 @@
# .pypirc.example
# Configuration file for uploading packages to Forgejo PyPI
#
# This file is a template - copy it to .pypirc and fill in your credentials:
# cp .pypirc.example .pypirc
#
# IMPORTANT: Never commit .pypirc to version control!
# It should already be in .gitignore
[distutils]
index-servers =
forgejo
[forgejo]
repository = https://git.him-tools.de/api/packages/HIM-public/pypi
username = __token__
password = YOUR_FORGEJO_ACCESS_TOKEN_HERE
# How to get your Forgejo access token:
# 1. Log in to your Forgejo instance: https://git.him-tools.de
# 2. Go to Settings > Applications > Generate New Token
# 3. Select 'write:package' scope
# 4. Copy the token and paste it above (replace YOUR_FORGEJO_ACCESS_TOKEN_HERE)
#
# Note: The username should always be "__token__" when using an access token

View file

@ -136,6 +136,64 @@ pytest
```
## Building & Publishing
### Update Version
Update the version number across all project files:
```bash
# PowerShell
.\update_version.ps1 0.2.0
# Python
python update_version.py 0.2.0
# Bash
./update_version.sh 0.2.0
```
### Build Wheel
Build distribution packages:
```bash
# PowerShell
.\build_wheel.ps1
# Python
python build_wheel.py
# Bash
./build_wheel.sh
```
### Upload to Forgejo PyPI
First, create your `.pypirc` configuration:
```bash
cp .pypirc.example .pypirc
# Edit .pypirc with your Forgejo access token
```
Then upload:
```bash
# PowerShell
.\upload_wheel_to_forgejo_pypi.ps1
# Bash
./upload_wheel_to_forgejo_pypi.sh
# Windows Batch
upload_wheel_to_forgejo_pypi.bat
```
The package will be available at:
`https://git.him-tools.de/HIM-public/-/packages/pypi/agravity-client`
## Licence
MIT

188
build_wheel.ps1 Normal file
View file

@ -0,0 +1,188 @@
# build_wheel.ps1
# Build wheel distribution for Agravity Client (PowerShell)
#
# Usage:
# .\build_wheel.ps1
#
# Requires:
# - Python 3.9+
# - setuptools>=65.0
# - wheel
# - build (recommended)
param(
[switch]$Clean = $false,
[switch]$Upload = $false
)
# Define symbols as variables to avoid encoding issues
$symSuccess = "[OK]"
$symError = "[!]"
$symBullet = "[*]"
# Color functions for output
function Write-Success {
Write-Host "$symSuccess $args" -ForegroundColor Green
}
function Write-Error-Custom {
Write-Host "$symError $args" -ForegroundColor Red
}
function Write-Header {
Write-Host ("=" * 70)
Write-Host $args
Write-Host ("=" * 70)
}
function Write-SubHeader {
Write-Host ("-" * 70)
Write-Host $args
Write-Host ("-" * 70)
}
# Main script
$projectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$distDir = Join-Path $projectRoot "dist"
$buildDir = Join-Path $projectRoot "build"
$eggInfoDir = Join-Path $projectRoot "agravity_client.egg-info"
Write-Header "Agravity Client - Wheel Builder (PowerShell)"
# Clean if requested
if ($Clean) {
Write-Host ""
Write-Host "Cleaning previous builds..."
@($distDir, $buildDir, $eggInfoDir) | ForEach-Object {
if (Test-Path $_) {
Remove-Item $_ -Recurse -Force -ErrorAction SilentlyContinue
Write-Success "Removed $_"
}
}
}
# Check if build directory exists from previous build
if (Test-Path $distDir) {
Write-Host ""
Write-Host "Cleaning dist directory..."
Remove-Item $distDir -Recurse -Force -ErrorAction SilentlyContinue
Write-Success "Removed old distributions"
}
# Install build requirements if needed
Write-Host ""
Write-Host "Checking build dependencies..."
$buildCheck = python -m pip list 2>$null | Select-String "build"
if (-not $buildCheck) {
Write-Host "Installing build tools..."
python -m pip install -q build setuptools wheel
if ($LASTEXITCODE -eq 0) {
Write-Success "Build tools installed"
} else {
Write-Error-Custom "Failed to install build tools"
exit 1
}
}
# Build
Write-SubHeader "Building distributions..."
Write-Host ""
Push-Location $projectRoot
try {
python -m build
if ($LASTEXITCODE -ne 0) {
Write-Error-Custom "Build failed"
exit 1
}
} finally {
Pop-Location
}
# Verify output
Write-SubHeader "Build Results"
Write-Host ""
if (!(Test-Path $distDir)) {
Write-Error-Custom "dist directory not created"
exit 1
}
$wheels = @(Get-ChildItem -Path $distDir -Filter "*.whl" -ErrorAction SilentlyContinue)
$sdists = @(Get-ChildItem -Path $distDir -Filter "*.tar.gz" -ErrorAction SilentlyContinue)
if ($wheels.Count -eq 0 -and $sdists.Count -eq 0) {
Write-Error-Custom "No distributions created"
exit 1
}
Write-Success "Build successful!"
Write-Host ""
if ($wheels.Count -gt 0) {
Write-Host "Wheels:"
$wheels | ForEach-Object {
$sizeMB = [Math]::Round($_.Length / 1MB, 2)
Write-Host " $symBullet $($_.Name) ($sizeMB MB)"
}
}
if ($sdists.Count -gt 0) {
Write-Host ""
Write-Host "Source Distributions:"
$sdists | ForEach-Object {
$sizeMB = [Math]::Round($_.Length / 1MB, 2)
Write-Host " $symBullet $($_.Name) ($sizeMB MB)"
}
}
Write-Host ""
Write-Success "Distributions saved to: $distDir"
# Installation instructions
Write-SubHeader "Installation Instructions"
Write-Host ""
if ($wheels.Count -gt 0) {
$wheel = $wheels[0]
Write-Host "Install the wheel locally:"
Write-Host " pip install `"$($wheel.FullName)`""
Write-Host ""
Write-Host "Or upload to PyPI:"
Write-Host " pip install twine"
Write-Host " twine upload dist/*"
Write-Host ""
}
# Optional upload
if ($Upload) {
Write-SubHeader "Uploading to PyPI..."
Write-Host ""
$twineCheck = python -m pip list 2>$null | Select-String "twine"
if (-not $twineCheck) {
Write-Host "Installing twine..."
python -m pip install -q twine
}
Write-Host "Running twine upload..."
Push-Location $projectRoot
try {
python -m twine upload dist/*
if ($LASTEXITCODE -eq 0) {
Write-Success "Upload complete!"
} else {
Write-Error-Custom "Upload failed"
exit 1
}
} finally {
Pop-Location
}
}
Write-Host ""
Write-Host "Done!"
Write-Host ""
exit 0

152
build_wheel.py Normal file
View file

@ -0,0 +1,152 @@
#!/usr/bin/env python
"""Build wheel distribution for Agravity Client.
This script builds wheel and source distributions for the Agravity Client package.
It requires setuptools and wheel to be installed.
Usage:
python build_wheel.py
Output:
- Wheels saved to dist/ directory
- Source distribution (sdist) also created for reference
"""
import shutil
import subprocess
import sys
from pathlib import Path
def main() -> int:
"""Build wheel distribution.
Returns:
Exit code (0 for success, 1 for failure)
"""
project_root = Path(__file__).parent
dist_dir = project_root / "dist"
print("=" * 70)
print("Agravity Client - Wheel Builder")
print("=" * 70)
# Clean previous builds
print("\nCleaning previous builds...")
if dist_dir.exists():
try:
shutil.rmtree(dist_dir)
print(f"✓ Removed {dist_dir}")
except OSError as e:
print(f"✗ Failed to remove {dist_dir}: {e}")
return 1
build_dir = project_root / "build"
if build_dir.exists():
try:
shutil.rmtree(build_dir)
print(f"✓ Removed {build_dir}")
except OSError as e:
print(f"✗ Failed to remove {build_dir}: {e}")
return 1
egg_info_dir = project_root / "agravity_client.egg-info"
if egg_info_dir.exists():
try:
shutil.rmtree(egg_info_dir)
print(f"✓ Removed {egg_info_dir}")
except OSError as e:
print(f"✗ Failed to remove {egg_info_dir}: {e}")
return 1
# Build wheel and sdist
print("\n" + "-" * 70)
print("Building distributions...")
print("-" * 70 + "\n")
try:
# Use python -m build for modern approach
result = subprocess.run(
[sys.executable, "-m", "build"],
cwd=project_root,
check=False
)
if result.returncode != 0:
print("\n✗ Build failed")
print("\nTrying alternative build method...")
# Fallback to direct setuptools invocation
result = subprocess.run(
[sys.executable, "setup.py", "sdist", "bdist_wheel"],
cwd=project_root,
check=False
)
if result.returncode != 0:
print("\n✗ Build failed with fallback method")
return 1
except FileNotFoundError:
# If 'build' module not available, use setup.py
print("Using setuptools directly...\n")
result = subprocess.run(
[sys.executable, "setup.py", "sdist", "bdist_wheel"],
cwd=project_root,
check=False
)
if result.returncode != 0:
print("\n✗ Build failed")
return 1
# Verify build output
print("\n" + "-" * 70)
print("Build Results")
print("-" * 70 + "\n")
if not dist_dir.exists():
print("✗ dist directory not created")
return 1
wheels = list(dist_dir.glob("*.whl"))
sdists = list(dist_dir.glob("*.tar.gz"))
if not wheels and not sdists:
print("✗ No distributions created")
return 1
print("✓ Build successful!\n")
if wheels:
print("Wheels:")
for wheel in wheels:
size_mb = wheel.stat().st_size / (1024 * 1024)
print(f"{wheel.name} ({size_mb:.2f} MB)")
if sdists:
print("\nSource Distributions:")
for sdist in sdists:
size_mb = sdist.stat().st_size / (1024 * 1024)
print(f"{sdist.name} ({size_mb:.2f} MB)")
print(f"\n✓ Distributions saved to: {dist_dir}")
# Installation instructions
print("\n" + "-" * 70)
print("Installation Instructions")
print("-" * 70 + "\n")
if wheels:
wheel = wheels[0]
print(f"Install the wheel locally:\n")
print(f" pip install {dist_dir / wheel.name}\n")
print(f"Or upload to PyPI:\n")
print(f" pip install twine")
print(f" twine upload dist/*\n")
return 0
if __name__ == "__main__":
sys.exit(main())

197
build_wheel.sh Normal file
View file

@ -0,0 +1,197 @@
#!/bin/bash
# build_wheel.sh - Build wheel distribution for Agravity Client
#
# Usage:
# ./build_wheel.sh [--clean] [--upload]
#
# Options:
# --clean Clean previous builds before building
# --upload Upload to PyPI after building
#
# Requires:
# - Python 3.9+
# - setuptools>=65.0
# - wheel
# - build (recommended)
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Functions
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
print_header() {
echo "========================================================================"
echo "$1"
echo "========================================================================"
}
print_subheader() {
echo "------------------------------------------------------------------------"
echo "$1"
echo "------------------------------------------------------------------------"
}
# Parse arguments
CLEAN=false
UPLOAD=false
while [[ $# -gt 0 ]]; do
case $1 in
--clean)
CLEAN=true
shift
;;
--upload)
UPLOAD=true
shift
;;
*)
echo "Unknown option: $1"
echo "Usage: $0 [--clean] [--upload]"
exit 1
;;
esac
done
# Get project root
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DIST_DIR="$PROJECT_ROOT/dist"
BUILD_DIR="$PROJECT_ROOT/build"
EGG_INFO_DIR="$PROJECT_ROOT/agravity_client.egg-info"
print_header "Agravity Client - Wheel Builder"
# Clean if requested
if [ "$CLEAN" = true ]; then
echo ""
echo "Cleaning previous builds..."
for dir in "$DIST_DIR" "$BUILD_DIR" "$EGG_INFO_DIR"; do
if [ -d "$dir" ]; then
rm -rf "$dir"
print_success "Removed $dir"
fi
done
fi
# Clean dist directory for fresh build
if [ -d "$DIST_DIR" ]; then
rm -rf "$DIST_DIR"
print_success "Removed old distributions"
fi
# Check build dependencies
echo ""
echo "Checking build dependencies..."
if ! python3 -m pip list 2>/dev/null | grep -q "^build "; then
echo "Installing build tools..."
python3 -m pip install -q build setuptools wheel
if [ $? -eq 0 ]; then
print_success "Build tools installed"
else
print_error "Failed to install build tools"
exit 1
fi
fi
# Build
print_subheader "Building distributions..."
echo ""
cd "$PROJECT_ROOT"
if ! python3 -m build; then
print_error "Build failed"
exit 1
fi
# Verify output
print_subheader "Build Results"
echo ""
if [ ! -d "$DIST_DIR" ]; then
print_error "dist directory not created"
exit 1
fi
# Count wheels and sdists
WHEEL_COUNT=$(find "$DIST_DIR" -maxdepth 1 -name "*.whl" 2>/dev/null | wc -l)
SDIST_COUNT=$(find "$DIST_DIR" -maxdepth 1 -name "*.tar.gz" 2>/dev/null | wc -l)
if [ $WHEEL_COUNT -eq 0 ] && [ $SDIST_COUNT -eq 0 ]; then
print_error "No distributions created"
exit 1
fi
print_success "Build successful!"
echo ""
if [ $WHEEL_COUNT -gt 0 ]; then
echo "Wheels:"
for wheel in "$DIST_DIR"/*.whl; do
SIZE=$(du -h "$wheel" | cut -f1)
echo "$(basename "$wheel") ($SIZE)"
done
fi
if [ $SDIST_COUNT -gt 0 ]; then
echo ""
echo "Source Distributions:"
for sdist in "$DIST_DIR"/*.tar.gz; do
SIZE=$(du -h "$sdist" | cut -f1)
echo "$(basename "$sdist") ($SIZE)"
done
fi
echo ""
print_success "Distributions saved to: $DIST_DIR"
# Installation instructions
print_subheader "Installation Instructions"
echo ""
if [ $WHEEL_COUNT -gt 0 ]; then
WHEEL=$(ls "$DIST_DIR"/*.whl | head -1)
echo "Install the wheel locally:"
echo " pip install \"$WHEEL\""
echo ""
echo "Or upload to PyPI:"
echo " pip install twine"
echo " twine upload dist/*"
echo ""
fi
# Optional upload
if [ "$UPLOAD" = true ]; then
print_subheader "Uploading to PyPI..."
echo ""
if ! python3 -m pip list 2>/dev/null | grep -q "^twine "; then
echo "Installing twine..."
python3 -m pip install -q twine
fi
echo "Running twine upload..."
cd "$PROJECT_ROOT"
if python3 -m twine upload dist/*; then
print_success "Upload complete!"
else
print_error "Upload failed"
exit 1
fi
fi
echo ""
echo "Done!"
echo ""
exit 0

82
update_version.ps1 Normal file
View file

@ -0,0 +1,82 @@
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$Version
)
function Test-VersionFormat {
param([string]$Ver)
$pattern = '^\d+\.\d+\.\d+(?:-[a-zA-Z0-9]+)?$'
return $Ver -match $pattern
}
function Update-FileVersion {
param(
[string]$FilePath,
[string]$Pattern,
[string]$NewVersion
)
try {
$content = Get-Content -Path $FilePath -Raw
$newContent = $content -replace $Pattern, $NewVersion
if ($content -eq $newContent) {
Write-Host "[OK] $(Split-Path -Leaf $FilePath) already up-to-date" -ForegroundColor Green
return $true
}
Set-Content -Path $FilePath -Value $newContent -NoNewline
Write-Host "[OK] Updated $(Split-Path -Leaf $FilePath)" -ForegroundColor Green
return $true
}
catch {
Write-Host "[ERROR] Error: $_" -ForegroundColor Red
return $false
}
}
if (-not (Test-VersionFormat $Version)) {
Write-Host "[ERROR] Invalid version format: $Version" -ForegroundColor Red
exit 1
}
$projectRoot = Split-Path -Parent $PSCommandPath
$pyprojectPath = Join-Path $projectRoot "pyproject.toml"
$initPath = Join-Path (Join-Path $projectRoot "agravity_client") "__init__.py"
Write-Host "======================================================================"
Write-Host "Updating Agravity Client to version $Version"
Write-Host "======================================================================"
$success = $true
if (Test-Path $pyprojectPath) {
$pattern = 'version = "[^"]+"'
$newVersion = "version = `"$Version`""
if (-not (Update-FileVersion $pyprojectPath $pattern $newVersion)) {
$success = $false
}
}
else {
Write-Host "[ERROR] pyproject.toml not found" -ForegroundColor Red
$success = $false
}
if (Test-Path $initPath) {
$pattern = '__version__ = "[^"]+"'
$newVersion = "__version__ = `"$Version`""
if (-not (Update-FileVersion $initPath $pattern $newVersion)) {
$success = $false
}
}
else {
Write-Host "[ERROR] init file not found" -ForegroundColor Red
$success = $false
}
Write-Host "======================================================================"
if ($success) {
Write-Host "[OK] Version successfully updated to $Version" -ForegroundColor Green
exit 0
}
else {
Write-Host "[ERROR] Update completed with errors" -ForegroundColor Red
exit 1
}

127
update_version.py Normal file
View file

@ -0,0 +1,127 @@
#!/usr/bin/env python
"""Update version across Agravity Client project files.
This script updates the version in:
- pyproject.toml
- agravity_client/__init__.py
Usage:
python update_version.py <version>
python update_version.py 0.2.0
python update_version.py 1.0.0
The version must follow semantic versioning (major.minor.patch).
"""
import re
import sys
from pathlib import Path
def validate_version(version: str) -> bool:
"""Validate semantic version format.
Args:
version: Version string to validate
Returns:
True if valid, False otherwise
"""
pattern = r'^\d+\.\d+\.\d+(?:-[a-zA-Z0-9]+)?$'
return bool(re.match(pattern, version))
def update_file(file_path: Path, old_pattern: str, new_version: str) -> bool:
"""Update version in a file.
Args:
file_path: Path to file to update
old_pattern: Regex pattern to find version
new_version: New version string
Returns:
True if successful, False otherwise
"""
try:
content = file_path.read_text()
updated_content = re.sub(old_pattern, new_version, content)
if content == updated_content:
print(f"{file_path.name} already up-to-date")
return True
file_path.write_text(updated_content)
print(f"✓ Updated {file_path.name}")
return True
except Exception as e:
print(f"✗ Error updating {file_path.name}: {e}")
return False
def main() -> int:
"""Update version in project files.
Returns:
Exit code (0 for success, 1 for failure)
"""
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <version>")
print(f"Example: {sys.argv[0]} 0.2.0")
return 1
new_version = sys.argv[1]
if not validate_version(new_version):
print(f"✗ Invalid version format: {new_version}")
print("Version must follow semantic versioning (major.minor.patch)")
print("Examples: 1.0.0, 0.2.0, 1.0.0-beta")
return 1
project_root = Path(__file__).parent
pyproject_path = project_root / "pyproject.toml"
init_path = project_root / "agravity_client" / "__init__.py"
print("=" * 70)
print(f"Updating Agravity Client to version {new_version}")
print("=" * 70)
success = True
# Update pyproject.toml
if pyproject_path.exists():
pattern = r'version = "[^"]+"'
success &= update_file(
pyproject_path,
pattern,
f'version = "{new_version}"'
)
else:
print(f"{pyproject_path} not found")
success = False
# Update __init__.py
if init_path.exists():
pattern = r'__version__ = "[^"]+"'
success &= update_file(
init_path,
pattern,
f'__version__ = "{new_version}"'
)
else:
print(f"{init_path} not found")
success = False
if success:
print("=" * 70)
print(f"✓ Version successfully updated to {new_version}")
print("=" * 70)
return 0
else:
print("=" * 70)
print("✗ Version update completed with errors")
print("=" * 70)
return 1
if __name__ == "__main__":
sys.exit(main())

123
update_version.sh Normal file
View file

@ -0,0 +1,123 @@
#!/bin/bash
# Update version across Agravity Client project files.
#
# This script updates the version in:
# - pyproject.toml
# - agravity_client/__init__.py
#
# Usage:
# ./update_version.sh <version>
# ./update_version.sh 0.2.0
#
# The version must follow semantic versioning (major.minor.patch).
set -euo pipefail
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
validate_version() {
local version=$1
if [[ ! $version =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$ ]]; then
return 1
fi
return 0
}
update_file() {
local file_path=$1
local pattern=$2
local new_version=$3
if [[ ! -f "$file_path" ]]; then
echo -e "${RED}✗ File not found: $file_path${NC}"
return 1
fi
# Check if content would change
local content
content=$(cat "$file_path")
# Use sed to update the file (handles both macOS and Linux)
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS requires -i '' for in-place editing
sed -i '' "$pattern" "$file_path"
else
# Linux
sed -i "$pattern" "$file_path"
fi
local new_content
new_content=$(cat "$file_path")
if [[ "$content" == "$new_content" ]]; then
echo -e "${GREEN}$(basename "$file_path") already up-to-date${NC}"
else
echo -e "${GREEN}✓ Updated $(basename "$file_path")${NC}"
fi
return 0
}
main() {
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <version>"
echo "Example: $0 0.2.0"
exit 1
fi
local new_version=$1
if ! validate_version "$new_version"; then
echo -e "${RED}✗ Invalid version format: $new_version${NC}"
echo -e "${YELLOW}Version must follow semantic versioning (major.minor.patch)${NC}"
echo -e "${YELLOW}Examples: 1.0.0, 0.2.0, 1.0.0-beta${NC}"
exit 1
fi
local project_root
project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local pyproject_path="$project_root/pyproject.toml"
local init_path="$project_root/agravity_client/__init__.py"
echo "======================================================================"
echo "Updating Agravity Client to version $new_version"
echo "======================================================================"
local success=true
# Update pyproject.toml
if [[ -f "$pyproject_path" ]]; then
local pattern_pyproject="s|version = \"[^\"]*\"|version = \"$new_version\"|g"
if ! update_file "$pyproject_path" "$pattern_pyproject"; then
success=false
fi
else
echo -e "${RED}$pyproject_path not found${NC}"
success=false
fi
# Update __init__.py
if [[ -f "$init_path" ]]; then
local pattern_init="s|__version__ = \"[^\"]*\"|__version__ = \"$new_version\"|g"
if ! update_file "$init_path" "$pattern_init"; then
success=false
fi
else
echo -e "${RED}$init_path not found${NC}"
success=false
fi
echo "======================================================================"
if [[ "$success" == true ]]; then
echo -e "${GREEN}✓ Version successfully updated to $new_version${NC}"
exit 0
else
echo -e "${RED}✗ Version update completed with errors${NC}"
exit 1
fi
}
main "$@"

View file

@ -0,0 +1,103 @@
@echo off
REM Upload wheel to Forgejo PyPI for Agravity Client
REM
REM Prerequisites:
REM 1. Create .pypirc file in project root
REM 2. Copy from .pypirc.example and add your credentials
REM
REM Usage:
REM upload_wheel_to_forgejo_pypi.bat [--build]
REM Options: --build Force rebuild before upload
setlocal enabledelayedexpansion
set PYPIRC_SRC=%CD%\.pypirc
set PYPIRC_DEST=%USERPROFILE%\.pypirc
echo.
echo ========================================================================
echo Agravity Client - Upload to Forgejo PyPI
echo ========================================================================
echo.
REM Check for .pypirc
if not exist ".pypirc" (
echo [!] .pypirc not found in project root!
echo.
echo Setup instructions:
echo 1. cp .pypirc.example .pypirc
echo 2. Edit .pypirc with your Forgejo credentials
echo 3. Run this script again
echo.
pause
exit /b 1
)
REM Copy .pypirc to user profile
echo Configuring credentials...
copy /Y "%PYPIRC_SRC%" "%PYPIRC_DEST%" > nul
REM Activate virtual environment (if exists)
if exist .venv\Scripts\activate.bat (
call .venv\Scripts\activate.bat
)
REM Install twine if needed
python -m pip list | find /I "twine" > nul
if errorlevel 1 (
echo Installing twine...
python -m pip install -q twine
)
cd /d "%~dp0"
REM Check for --build flag
if "%~1"=="--build" (
echo Building wheel (forced)...
rmdir /s /q dist > nul 2>&1
python build_wheel.py
if errorlevel 1 (
del "%PYPIRC_DEST%"
if exist .venv\Scripts\deactivate.bat call .venv\Scripts\deactivate.bat
exit /b 1
)
) else (
REM Build wheel if not present
if not exist dist\*.whl (
echo Building wheel...
python build_wheel.py
if errorlevel 1 (
del "%PYPIRC_DEST%"
if exist .venv\Scripts\deactivate.bat call .venv\Scripts\deactivate.bat
exit /b 1
)
)
)
REM Upload to Forgejo PyPI
echo.
echo ========================================================================
echo Uploading to Forgejo PyPI...
echo ========================================================================
echo.
twine upload -r forgejo dist\*.whl
set UPLOAD_RESULT=%errorlevel%
REM Cleanup
del "%PYPIRC_DEST%"
if exist .venv\Scripts\deactivate.bat call .venv\Scripts\deactivate.bat
echo.
echo ========================================================================
if %UPLOAD_RESULT% equ 0 (
echo Upload successful!
) else (
echo Upload failed
)
echo ========================================================================
echo.
endlocal
pause
exit /b %UPLOAD_RESULT%

View file

@ -0,0 +1,130 @@
# upload_wheel_to_forgejo_pypi.ps1
# Upload wheel to Forgejo PyPI for Agravity Client
#
# Prerequisites:
# 1. Create .pypirc file with your Forgejo credentials
# 2. Copy from .pypirc.example and add your credentials
#
# Usage:
# .\upload_wheel_to_forgejo_pypi.ps1
param(
[switch]$Build = $false,
[switch]$Help = $false
)
if ($Help) {
Write-Host @"
Upload wheel to Forgejo PyPI for Agravity Client
USAGE:
.\upload_wheel_to_forgejo_pypi.ps1 [-Build]
OPTIONS:
-Build Force rebuild wheel before uploading
-Help Display this help message
SETUP:
1. Create .pypirc in project root
2. Copy from .pypirc.example as template
3. Add your Forgejo repository URL and credentials:
[distutils]
index-servers = forgejo
[forgejo]
repository = https://git.him-tools.de/api/packages/HIM-public/pypi
username = __token__
password = YOUR_ACCESS_TOKEN
4. Keep .pypirc in .gitignore (already added)
EXAMPLE:
.\upload_wheel_to_forgejo_pypi.ps1 # Upload existing wheel
.\upload_wheel_to_forgejo_pypi.ps1 -Build # Rebuild and upload
"@
exit 0
}
$projectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$pypiRcSrc = Join-Path $projectRoot ".pypirc"
$pypiRcDest = Join-Path $env:USERPROFILE ".pypirc"
Write-Host ""
Write-Host "========================================================================"
Write-Host "Agravity Client - Upload to Forgejo PyPI"
Write-Host "========================================================================"
Write-Host ""
# Check for .pypirc
if (!(Test-Path $pypiRcSrc)) {
Write-Host "[!] .pypirc not found in project root!" -ForegroundColor Red
Write-Host ""
Write-Host "Setup instructions:"
Write-Host " 1. cp .pypirc.example .pypirc"
Write-Host " 2. Edit .pypirc with your Forgejo credentials"
Write-Host " 3. Run this script again"
Write-Host ""
Write-Host "For help: .\upload_wheel_to_forgejo_pypi.ps1 -Help"
Write-Host ""
exit 1
}
# Copy .pypirc to user profile
Write-Host "Configuring credentials..."
Copy-Item -Path $pypiRcSrc -Destination $pypiRcDest -Force
# Activate virtual environment
$activateScript = Join-Path $projectRoot ".venv\Scripts\Activate.ps1"
if (Test-Path $activateScript) {
& $activateScript
}
# Install/upgrade twine if needed
python -m pip list | Select-String "^twine " > $null
if ($LASTEXITCODE -ne 0) {
Write-Host "Installing twine..."
python -m pip install -q twine
}
# Build wheel if requested or not present
Push-Location $projectRoot
if ($Build -or !(Get-ChildItem -Path "dist" -Filter "*.whl" -ErrorAction SilentlyContinue)) {
if ($Build) {
Write-Host "Building wheel (forced)..."
Remove-Item "dist" -Recurse -Force -ErrorAction SilentlyContinue
} else {
Write-Host "Building wheel..."
}
python build_wheel.py
if ($LASTEXITCODE -ne 0) {
Remove-Item $pypiRcDest -Force
exit 1
}
}
# Upload to Forgejo PyPI
Write-Host ""
Write-Host "========================================================================"
Write-Host "Uploading to Forgejo PyPI..."
Write-Host "========================================================================"
Write-Host ""
twine upload -r forgejo dist/*.whl
$uploadResult = $LASTEXITCODE
Pop-Location
# Cleanup credentials
Remove-Item $pypiRcDest -Force
Write-Host ""
Write-Host "========================================================================"
if ($uploadResult -eq 0) {
Write-Host "Upload successful!" -ForegroundColor Green
} else {
Write-Host "Upload failed" -ForegroundColor Red
}
Write-Host "========================================================================"
Write-Host ""
exit $uploadResult

View file

@ -0,0 +1,100 @@
#!/bin/bash
# upload_wheel_to_forgejo_pypi.sh
# Upload wheel to Forgejo PyPI for Agravity Client
#
# Prerequisites:
# 1. Create .pypirc file in project root
# 2. Copy from .pypirc.example and add your credentials
#
# Usage:
# ./upload_wheel_to_forgejo_pypi.sh [--build]
# Options: --build Force rebuild before upload
set -e
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PYPIRC_SRC="$PROJECT_ROOT/.pypirc"
PYPIRC_DEST="$HOME/.pypirc"
echo ""
echo "========================================================================"
echo "Agravity Client - Upload to Forgejo PyPI"
echo "========================================================================"
echo ""
# Check for .pypirc
if [ ! -f "$PYPIRC_SRC" ]; then
echo "[!] .pypirc not found in project root!"
echo ""
echo "Setup instructions:"
echo " 1. cp .pypirc.example .pypirc"
echo " 2. Edit .pypirc with your Forgejo credentials"
echo " 3. Run this script again"
echo ""
exit 1
fi
# Copy .pypirc to user home
echo "Configuring credentials..."
cp "$PYPIRC_SRC" "$PYPIRC_DEST"
chmod 600 "$PYPIRC_DEST"
# Activate virtual environment (if exists)
if [ -f "$PROJECT_ROOT/.venv/bin/activate" ]; then
source "$PROJECT_ROOT/.venv/bin/activate"
fi
# Install twine if needed
if ! pip list 2>/dev/null | grep -q "^twine "; then
echo "Installing twine..."
pip install -q twine
fi
# Check for --build flag
if [ "$1" = "--build" ]; then
echo "Building wheel (forced)..."
rm -rf "$PROJECT_ROOT/dist"
cd "$PROJECT_ROOT"
python build_wheel.py
if [ $? -ne 0 ]; then
rm -f "$PYPIRC_DEST"
exit 1
fi
else
# Build wheel if not present
if ! ls "$PROJECT_ROOT/dist"/*.whl > /dev/null 2>&1; then
echo "Building wheel..."
cd "$PROJECT_ROOT"
python build_wheel.py
if [ $? -ne 0 ]; then
rm -f "$PYPIRC_DEST"
exit 1
fi
fi
fi
# Upload to Forgejo PyPI
echo ""
echo "========================================================================"
echo "Uploading to Forgejo PyPI..."
echo "========================================================================"
echo ""
cd "$PROJECT_ROOT"
twine upload -r forgejo dist/*.whl
UPLOAD_RESULT=$?
# Cleanup
rm -f "$PYPIRC_DEST"
echo ""
echo "========================================================================"
if [ $UPLOAD_RESULT -eq 0 ]; then
echo "Upload successful!"
else
echo "Upload failed"
fi
echo "========================================================================"
echo ""
exit $UPLOAD_RESULT