Add Forgejo PyPI support and update .gitignore for sensitive files

This commit is contained in:
claudi 2026-02-20 09:55:42 +01:00
parent b8a7fb903e
commit 4fd9f13f36
7 changed files with 636 additions and 55 deletions

5
.gitignore vendored
View file

@ -104,6 +104,11 @@ ENV/
env.bak/ env.bak/
venv.bak/ venv.bak/
# Environment and credentials
.env
.env.local
.pypirc
# Spyder project settings # Spyder project settings
.spyderproject .spyderproject
.spyproject .spyproject

22
.pypirc.example Normal file
View file

@ -0,0 +1,22 @@
[distutils]
index-servers =
forgejo
[forgejo]
# Forgejo PyPI Repository Configuration
# Repository: https://your-forgejo-instance.com/api/packages/{username}/pypi
# Documentation: https://docs.forgejo.org/en/latest/usage/packages/pypi/
#
# To use this file:
# 1. Replace YOUR_FORGEJO_INSTANCE with your Forgejo URL
# 2. Replace YOUR_USERNAME with your Forgejo username
# 3. Replace YOUR_ACCESS_TOKEN with your Forgejo personal access token
# (Generate at: https://your-forgejo-instance.com/user/settings/applications)
# 4. Keep this file secure (credentials inside!)
#
# WARNING: This file contains sensitive credentials.
# Add to .gitignore to prevent accidental commits!
repository = https://git.him-tools.de/api/packages/HIM-public/pypi/
username = __token__
password = YOUR_ACCESS_TOKEN

283
BUILD.md
View file

@ -151,68 +151,217 @@ Or with dev dependencies:
pip install -e ".[dev]" pip install -e ".[dev]"
``` ```
## Uploading to PyPI ## Uploading to Forgejo PyPI
### Prerequisites This project uses **Forgejo PyPI** for package distribution, not the public PyPI. Forgejo is a self-hosted Git service with integrated package registry support.
1. Create PyPI account at https://pypi.org/ ### Setup Forgejo PyPI
2. Create PyPI token: https://pypi.org/manage/account/tokens/
3. Configure credentials
### Using twine #### Step 1: Create .pypirc Configuration
Copy the example configuration:
```bash ```bash
# Install twine cp .pypirc.example .pypirc
pip install twine
# Upload to PyPI (after building)
twine upload dist/*
# Or to TestPyPI for testing first
twine upload -r testpypi dist/*
``` ```
### Authentication Edit `.pypirc` with your Forgejo details:
**Option 1: Using .pypirc file**
Create `~/.pypirc`:
```ini ```ini
[distutils] [distutils]
index-servers = index-servers =
pypi forgejo
testpypi
[pypi] [forgejo]
repository = https://upload.pypi.org/legacy/ repository = https://your-forgejo-instance.com/api/packages/YOUR_USERNAME/pypi
username = __token__ username = __token__
password = pypi_your_token_here password = YOUR_ACCESS_TOKEN
[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = pypi_your_test_token_here
``` ```
**Option 2: Interactive prompt** #### Step 2: Generate Forgejo Personal Access Token
twine will prompt for username and password when uploading. 1. Visit your Forgejo instance: `https://your-forgejo-instance.com`
2. Go to: **User Settings** → **Applications**
3. Click **Create New Token**
4. Name it: `PyPI Upload`
5. Grant scope: **write:packages**
6. Copy the generated token
7. Paste into `.pypirc` as `password`
### Upload to Test PyPI First #### Step 3: Secure .pypirc
Before uploading to production, test with TestPyPI: **IMPORTANT:** Add `.pypirc` to `.gitignore` to prevent committing credentials!
```bash ```bash
twine upload -r testpypi dist/* echo ".pypirc" >> .gitignore
git add .gitignore
git commit -m "chore: add .pypirc to gitignore"
``` ```
Then test installation: ### Uploading to Forgejo PyPI
**Requirement:** twine must be installed (see Prerequisites section above)
#### Option 1: Using PowerShell Script (Windows - Recommended)
```powershell
# Activate virtual environment first
.\.venv\Scripts\Activate.ps1
# Upload existing wheel
.\upload_wheel_to_forgejo_pypi.ps1
# Rebuild and upload
.\upload_wheel_to_forgejo_pypi.ps1 -Build
# Show help
.\upload_wheel_to_forgejo_pypi.ps1 -Help
```
#### Option 2: Using Batch Script (Windows)
```batch
upload_wheel_to_forgejo_pypi.bat
REM Rebuild and upload
upload_wheel_to_forgejo_pypi.bat --build
```
#### Option 3: Using Shell Script (Unix/Linux)
```bash ```bash
pip install -i https://test.pypi.org/simple/ elytra-pim-client==0.1.0 # Make script executable (first time only)
chmod +x upload_wheel_to_forgejo_pypi.sh
# Upload existing wheel
./upload_wheel_to_forgejo_pypi.sh
# Rebuild and upload
./upload_wheel_to_forgejo_pypi.sh --build
# Show help
./upload_wheel_to_forgejo_pypi.sh --help
``` ```
#### Option 4: Using twine Directly
```bash
# Activate virtual environment
.venv\Scripts\activate # Windows
source .venv/bin/activate # macOS/Linux
# Upload wheel to Forgejo (twine is already in requirements.txt)
twine upload -r forgejo dist/*.whl
```
### What the Upload Scripts Do
1. **Load credentials** - Reads .pypirc configuration
2. **Setup environment** - Copies .pypirc to user home directory temporarily
3. **Activate venv** - Sets up Python virtual environment
4. **Build wheel** - Builds wheel if not present (or with --build flag)
5. **Upload** - Uploads wheel to Forgejo PyPI repository using twine
6. **Cleanup** - Removes temporary credentials from home directory
7. **Deactivate** - Deactivates virtual environment
### Accessing Your Package
After upload, your package is available in the Forgejo PyPI repository:
```bash
# Install from Forgejo PyPI
pip install --index-url https://your-forgejo-instance.com/api/packages/YOUR_USERNAME/pypi/simple/ elytra-pim-client
# Or add to requirements.txt
-i https://your-forgejo-instance.com/api/packages/YOUR_USERNAME/pypi/simple/
elytra-pim-client
```
### Troubleshooting Upload Issues
#### "Upload failed" Error
**Check:** Verify .pypirc configuration
```ini
[forgejo]
repository = https://correct-url.com/api/packages/USERNAME/pypi
username = __token__
password = VALID_TOKEN
```
**Verify:** Token has correct permissions
- Token must have `write:packages` scope
- Visit: `https://your-forgejo-instance.com/user/settings/applications`
**Network:** Ensure Forgejo instance is reachable
```bash
curl https://your-forgejo-instance.com/api/v1/user
```
#### ".pypirc not found" Error
Create it from template:
```bash
cp .pypirc.example .pypirc
# Then edit with your credentials
```
#### "twine: command not found" Error
**Solution:** twine is included in `requirements.txt` as a development dependency. Install all dependencies:
```bash
pip install -r requirements.txt
```
### Example Workflow
```bash
# 1. Setup Forgejo PyPI (first time only)
cp .pypirc.example .pypirc
# Edit .pypirc with your Forgejo repository URL and credentials
echo ".pypirc" >> .gitignore
git add .gitignore
git commit -m "chore: add .pypirc to gitignore"
# 2. Make code changes
git commit -am "feat: add new feature"
# 3. Update version in pyproject.toml
# version = "0.2.0"
# 4. Build and upload to Forgejo PyPI
.\upload_wheel_to_forgejo_pypi.ps1 # PowerShell
# or
./upload_wheel_to_forgejo_pypi.sh # Bash/Shell
# or
./upload_wheel_to_forgejo_pypi.bat # Batch
# 5. Tag and push release
git tag v0.2.0
git push origin v0.2.0
```
## Uploading to Public PyPI (Future)
To upload to public PyPI instead of Forgejo:
1. Install twine: `pip install twine`
2. Create account at https://pypi.org/
3. Generate token at https://pypi.org/manage/account/tokens/
4. Create `.pypirc`:
```ini
[distutils]
index-servers =
pypi
[pypi]
repository = https://upload.pypi.org/legacy/
username = __token__
password = pypi_your_token_here
```
5. Upload: `twine upload -r pypi dist/*.whl`
## Versioning ## Versioning
### Version Format ### Version Format
@ -325,53 +474,77 @@ python -m build --verbose
``` ```
elytra_client/ elytra_client/
├── build_wheel.py # Python build script (all platforms) ├── build_wheel.py # Python build script (all platforms)
├── build_wheel.ps1 # PowerShell build script (Windows) ├── build_wheel.ps1 # PowerShell build script (Windows)
├── build_wheel.sh # Shell build script (Unix/Linux) ├── build_wheel.sh # Shell build script (Unix/Linux)
├── build_requirements.txt # Build dependencies ├── upload_wheel_to_forgejo_pypi.bat # Batch upload script (Windows)
├── setup.py # Setup configuration (legacy compatibility) ├── upload_wheel_to_forgejo_pypi.ps1 # PowerShell upload script (Windows)
├── pyproject.toml # Modern build configuration (PEP 517/518) ├── upload_wheel_to_forgejo_pypi.sh # Shell upload script (Unix/Linux)
├── MANIFEST.in # (Optional) File inclusion rules ├── .pypirc.example # Forgejo PyPI configuration template
└── dist/ # Output directory for distributions ├── .pypirc # Forgejo PyPI credentials (in .gitignore!)
├── build_requirements.txt # Build dependencies
├── setup.py # Setup configuration (legacy compatibility)
├── pyproject.toml # Modern build configuration (PEP 517/518)
└── dist/ # Output directory for distributions
├── elytra_pim_client-0.1.0-py3-none-any.whl ├── elytra_pim_client-0.1.0-py3-none-any.whl
└── elytra_pim_client-0.1.0.tar.gz └── elytra_pim_client-0.1.0.tar.gz
``` ```
## Best Practices ## Best Practices
1. **Always test before releasing** 1. **Setup Forgejo PyPI (first time only)**
```bash ```bash
twine upload -r testpypi dist/* cp .pypirc.example .pypirc
pip install -i https://test.pypi.org/simple/ elytra-pim-client==0.1.0 # Edit .pypirc with your Forgejo credentials
echo ".pypirc" >> .gitignore
``` ```
2. **Increment version for each release** 2. **Complete release workflow**
```bash
# Update version in pyproject.toml
# version = "0.2.0"
# Build and upload
.\upload_wheel_to_forgejo_pypi.ps1
# Tag and push
git tag v0.2.0
git push origin v0.2.0
```
3. **Increment version for each release**
- Patch: Bug fixes (0.1.1) - Patch: Bug fixes (0.1.1)
- Minor: New features (0.2.0) - Minor: New features (0.2.0)
- Major: Breaking changes (1.0.0) - Major: Breaking changes (1.0.0)
3. **Clean before rebuilding** 4. **Clean before rebuilding**
```bash ```bash
python build_wheel.py # Automatically cleans python build_wheel.py # Automatically cleans
# Or manually # Or manually
rm -rf dist/ build/ *.egg-info/ rm -rf dist/ build/ *.egg-info/
``` ```
4. **Keep dependencies minimal** 5. **Keep dependencies minimal**
- Only required packages in `dependencies` - Only required packages in `dependencies`
- Development tools in `[project.optional-dependencies]` - Development tools in `[project.optional-dependencies]`
5. **Document changes** 6. **Use .pypirc template**
- Update CHANGELOG.md (if present) - Never commit `.pypirc` with real credentials
- Update version in pyproject.toml - Always keep `.pypirc` in `.gitignore`
- Create git tag for release - Share `.pypirc.example` with template values
7. **Secure credential handling**
- Use Forgejo personal access tokens with limited scope
- Rotate tokens regularly
- Never share tokens or .pypirc files
## Resources ## Resources
- [Forgejo Documentation](https://docs.forgejo.org/)
- [Forgejo PyPI Package Registry](https://docs.forgejo.org/en/latest/usage/packages/pypi/)
- [Python Packaging Guide](https://packaging.python.org/) - [Python Packaging Guide](https://packaging.python.org/)
- [PEP 517 - Build System Interface](https://www.python.org/dev/peps/pep-0517/) - [PEP 517 - Build System Interface](https://www.python.org/dev/peps/pep-0517/)
- [PEP 518 - pyproject.toml](https://www.python.org/dev/peps/pep-0518/) - [PEP 518 - pyproject.toml](https://www.python.org/dev/peps/pep-0518/)
- [PEP 440 - Version Identification](https://www.python.org/dev/peps/pep-0440/) - [PEP 440 - Version Identification](https://www.python.org/dev/peps/pep-0440/)
- [setuptools Documentation](https://setuptools.pypa.io/) - [setuptools Documentation](https://setuptools.pypa.io/)
- [twine Documentation](https://twine.readthedocs.io/) - [twine Documentation](https://twine.readthedocs.io/)
- [PyPI Help](https://pypi.org/help/)

View file

@ -9,3 +9,4 @@ black>=23.0.0
isort>=5.12.0 isort>=5.12.0
flake8>=6.0.0 flake8>=6.0.0
mypy>=1.0.0 mypy>=1.0.0
twine>=4.0.0

View file

@ -0,0 +1,153 @@
@echo off
REM Upload wheel to Forgejo PyPI for Elytra PIM 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 Elytra PIM 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
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%"
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%"
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%"
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%
if errorlevel 1 (
echo Error: Build failed
del "%PYPIRC_DEST%"
call .venv\Scripts\deactivate.bat
pause
exit /b 1
)
)
)
REM Upload to Forgejo PyPI
echo.
echo ========================================================================
echo Uploading to Forgejo PyPI...
echo ========================================================================
echo.
twine upload -r forgejo dist\*.whl
if errorlevel 1 (
echo.
echo Error: Upload failed
echo.
echo Troubleshooting:
echo - Verify .pypirc has correct credentials
echo - Check Forgejo instance is reachable
echo - Ensure access token is valid
echo - Visit: https://your-forgejo-instance.com/user/settings/applications
echo.
del "%PYPIRC_DEST%"
call .venv\Scripts\deactivate.bat
pause
exit /b 1
)
REM Cleanup
echo.
echo ========================================================================
echo Upload complete!
echo ========================================================================
echo.
call .venv\Scripts\deactivate.bat
del "%PYPIRC_DEST%"
echo [OK] Virtual environment deactivated
echo [OK] Credentials removed
echo.
echo Your package is now available in your Forgejo PyPI repository.
echo.
pause
endlocal

View file

@ -0,0 +1,129 @@
# upload_wheel_to_forgejo_pypi.ps1
# Upload wheel to Forgejo PyPI for Elytra PIM 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 Elytra PIM 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://your-forgejo-instance.com/api/packages/YOUR_USERNAME/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 "Elytra PIM 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"
& $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,98 @@
#!/bin/bash
# upload_wheel_to_forgejo_pypi.sh
# Upload wheel to Forgejo PyPI for Elytra PIM 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 "Elytra PIM 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
source "$PROJECT_ROOT/.venv/bin/activate"
# 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