diff --git a/.gitignore b/.gitignore index 1134237..dd2cb32 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,6 @@ dist/ *.egg-info/ .eggs/ pip-wheel-metadata/ -.pypirc # Test and coverage output .pytest_cache/ diff --git a/.pypirc.example b/.pypirc.example deleted file mode 100644 index 568588d..0000000 --- a/.pypirc.example +++ /dev/null @@ -1,7 +0,0 @@ -[distutils] -index-servers = forgejo - -[forgejo] -repository = https://git.him-tools.de/api/packages/HIM-public/pypi -username = __token__ -password = YOUR_FORGEJO_ACCESS_TOKEN \ No newline at end of file diff --git a/README.md b/README.md index 7f0e1be..7ae5473 100644 --- a/README.md +++ b/README.md @@ -43,52 +43,6 @@ Install development dependencies when you want tests and code generation tooling & .\.venv\Scripts\python.exe -m pip install -e .[dev] ``` -## Packaging - -Print the current package version: - -```powershell -& .\.venv\Scripts\python.exe .\scripts\set_version.py --print-current -``` - -Update the package version in `pyproject.toml`: - -```powershell -& .\.venv\Scripts\python.exe .\scripts\set_version.py 0.1.1 -``` - -Build a wheel into `dist\`: - -```powershell -& .\.venv\Scripts\python.exe .\scripts\build_wheel.py -``` - -Set the version and build the wheel in one step: - -```powershell -& .\.venv\Scripts\python.exe .\scripts\build_wheel.py --version 0.1.1 -``` - -Upload the wheel to the Forgejo package registry: - -```powershell -.\upload_wheel_to_forgejo_pypi.ps1 -``` - -Force a rebuild before upload: - -```powershell -.\upload_wheel_to_forgejo_pypi.ps1 -Build -``` - -Build a specific version and upload it: - -```powershell -.\upload_wheel_to_forgejo_pypi.ps1 -Build -Version 0.1.1 -``` - -Create `.pypirc` in the project root from `.pypirc.example` and fill in your Forgejo token before uploading. - Create a client with your eBay credentials: ```python diff --git a/pyproject.toml b/pyproject.toml index 12b1bc8..6c6ed98 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,11 +17,9 @@ dependencies = [ [project.optional-dependencies] dev = [ - "build>=1.2,<2", "datamodel-code-generator>=0.28,<0.31", "pytest>=8,<9", "pytest-httpx>=0.35,<0.36", - "twine>=6,<7", ] [tool.setuptools.packages.find] diff --git a/scripts/build_wheel.py b/scripts/build_wheel.py deleted file mode 100644 index a726235..0000000 --- a/scripts/build_wheel.py +++ /dev/null @@ -1,87 +0,0 @@ -from __future__ import annotations - -import argparse -import importlib.util -import shutil -import subprocess -import sys -from pathlib import Path - -from set_version import PYPROJECT_PATH, extract_project_version, write_project_version - - -ROOT = Path(__file__).resolve().parent.parent - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description="Build a wheel for the project.") - parser.add_argument("--version", help="Optionally set the project version before building.") - parser.add_argument("--outdir", default="dist", help="Directory where the wheel will be written.") - parser.add_argument("--no-clean", action="store_true", help="Keep existing build and output directories.") - return parser.parse_args() - - -def resolve_output_dir(outdir: str) -> Path: - output_dir = Path(outdir) - if not output_dir.is_absolute(): - output_dir = ROOT / output_dir - return output_dir - - -def ensure_build_dependency() -> None: - if importlib.util.find_spec("build") is None: - raise RuntimeError( - 'Missing dependency "build". Install development dependencies with '\ - '"python -m pip install -e .[dev]" or install "build" directly.' - ) - - -def clean_build_artifacts(output_dir: Path) -> None: - for path in (ROOT / "build", output_dir): - if path.exists(): - shutil.rmtree(path) - - -def build_wheel(output_dir: Path) -> None: - command = [ - sys.executable, - "-m", - "build", - "--wheel", - "--outdir", - str(output_dir), - ] - subprocess.run(command, check=True, cwd=ROOT) - - -def main() -> int: - args = parse_args() - output_dir = resolve_output_dir(args.outdir) - - if args.version: - previous_version, updated_version = write_project_version(PYPROJECT_PATH, args.version) - if previous_version == updated_version: - print(f"Version already set to {updated_version}") - else: - print(f"Updated version: {previous_version} -> {updated_version}") - - ensure_build_dependency() - - if not args.no_clean: - clean_build_artifacts(output_dir) - output_dir.mkdir(parents=True, exist_ok=True) - - version = extract_project_version(PYPROJECT_PATH.read_text(encoding="utf-8")) - print(f"Building wheel for version {version} into {output_dir}") - build_wheel(output_dir) - - wheels = sorted(output_dir.glob("*.whl")) - if not wheels: - raise RuntimeError("Build completed without producing a wheel file.") - for wheel in wheels: - print(f"Built wheel: {wheel}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) \ No newline at end of file diff --git a/scripts/set_version.py b/scripts/set_version.py deleted file mode 100644 index 009bfab..0000000 --- a/scripts/set_version.py +++ /dev/null @@ -1,88 +0,0 @@ -from __future__ import annotations - -import argparse -import re -import tomllib -from pathlib import Path - - -ROOT = Path(__file__).resolve().parent.parent -PYPROJECT_PATH = ROOT / "pyproject.toml" -PROJECT_VERSION_PATTERN = re.compile( - r'(?ms)(^\[project\]\s*$.*?^version\s*=\s*")([^"\r\n]+)(")' -) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description="Update the project version in pyproject.toml.") - parser.add_argument("version", nargs="?", help="New project version.") - parser.add_argument("--print-current", action="store_true", help="Print the current project version.") - args = parser.parse_args() - if not args.print_current and not args.version: - parser.error("Provide a version or use --print-current.") - return args - - -def validate_version(version: str) -> str: - normalized = version.strip() - if not normalized: - raise ValueError("Version cannot be empty.") - if normalized != version: - raise ValueError("Version cannot start or end with whitespace.") - if any(character.isspace() for character in version): - raise ValueError("Version cannot contain whitespace.") - if '"' in version or "'" in version: - raise ValueError("Version cannot contain quote characters.") - return version - - -def extract_project_version(pyproject_text: str) -> str: - match = PROJECT_VERSION_PATTERN.search(pyproject_text) - if match is None: - raise ValueError("Could not find [project].version in pyproject.toml.") - return match.group(2) - - -def set_project_version_in_text(pyproject_text: str, new_version: str) -> str: - validate_version(new_version) - - def replace(match: re.Match[str]) -> str: - return f"{match.group(1)}{new_version}{match.group(3)}" - - updated_text, replacements = PROJECT_VERSION_PATTERN.subn(replace, pyproject_text, count=1) - if replacements != 1: - raise ValueError("Could not update [project].version in pyproject.toml.") - - tomllib.loads(updated_text) - return updated_text - - -def write_project_version(pyproject_path: Path, new_version: str) -> tuple[str, str]: - original_text = pyproject_path.read_text(encoding="utf-8") - current_version = extract_project_version(original_text) - updated_text = set_project_version_in_text(original_text, new_version) - - if updated_text != original_text: - pyproject_path.write_text(updated_text, encoding="utf-8") - - return current_version, new_version - - -def main() -> int: - args = parse_args() - pyproject_text = PYPROJECT_PATH.read_text(encoding="utf-8") - - if args.print_current: - print(extract_project_version(pyproject_text)) - return 0 - - previous_version, updated_version = write_project_version(PYPROJECT_PATH, args.version) - if previous_version == updated_version: - print(f"Version already set to {updated_version}") - else: - print(f"Updated version: {previous_version} -> {updated_version}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) \ No newline at end of file diff --git a/tests/test_release_scripts.py b/tests/test_release_scripts.py deleted file mode 100644 index f557a29..0000000 --- a/tests/test_release_scripts.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import annotations - -import sys -import tomllib -from pathlib import Path - - -ROOT = Path(__file__).resolve().parent.parent -sys.path.insert(0, str(ROOT / "scripts")) - -from set_version import extract_project_version, set_project_version_in_text, write_project_version - - -def test_extract_project_version_reads_project_version() -> None: - pyproject_text = ( - "[build-system]\n" - 'requires = ["setuptools>=69", "wheel"]\n\n' - "[project]\n" - 'name = "ebay-rest-client"\n' - 'version = "0.1.0"\n' - ) - - assert extract_project_version(pyproject_text) == "0.1.0" - - -def test_set_project_version_in_text_updates_project_version_only() -> None: - pyproject_text = ( - "[build-system]\n" - 'requires = ["setuptools>=69", "wheel"]\n\n' - "[project]\n" - 'name = "ebay-rest-client"\n' - 'version = "0.1.0"\n' - 'description = "test package"\n' - ) - - updated_text = set_project_version_in_text(pyproject_text, "1.2.3") - - assert extract_project_version(updated_text) == "1.2.3" - assert tomllib.loads(updated_text)["project"]["version"] == "1.2.3" - - -def test_write_project_version_updates_file(tmp_path: Path) -> None: - pyproject_path = tmp_path / "pyproject.toml" - pyproject_path.write_text( - "[project]\n" - 'name = "ebay-rest-client"\n' - 'version = "0.1.0"\n', - encoding="utf-8", - ) - - previous_version, updated_version = write_project_version(pyproject_path, "2.0.0") - - assert previous_version == "0.1.0" - assert updated_version == "2.0.0" - assert tomllib.loads(pyproject_path.read_text(encoding="utf-8"))["project"]["version"] == "2.0.0" \ No newline at end of file diff --git a/upload_wheel_to_forgejo_pypi.ps1 b/upload_wheel_to_forgejo_pypi.ps1 deleted file mode 100644 index c179e2c..0000000 --- a/upload_wheel_to_forgejo_pypi.ps1 +++ /dev/null @@ -1,131 +0,0 @@ -param( - [switch]$Build = $false, - [string]$Version, - [switch]$Help = $false -) - -Set-StrictMode -Version Latest -$ErrorActionPreference = "Stop" - -function Show-Help { - Write-Host @" -Upload wheel to the Forgejo PyPI registry for ebay-rest-client - -USAGE: - .\upload_wheel_to_forgejo_pypi.ps1 [-Build] [-Version ] - -OPTIONS: - -Build Force a rebuild before uploading - -Version Set the package version before building - -Help Display this help message - -SETUP: - 1. Copy .pypirc.example to .pypirc in the project root - 2. Add your Forgejo access token to .pypirc - 3. Run this script again - -EXAMPLES: - .\upload_wheel_to_forgejo_pypi.ps1 - .\upload_wheel_to_forgejo_pypi.ps1 -Build - .\upload_wheel_to_forgejo_pypi.ps1 -Build -Version 0.1.1 -"@ -} - -if ($Help) { - Show-Help - exit 0 -} - -$projectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path -$python = Join-Path $projectRoot ".venv\Scripts\python.exe" -$pypiRcPath = Join-Path $projectRoot ".pypirc" -$buildScript = Join-Path $projectRoot "scripts\build_wheel.py" -$distPath = Join-Path $projectRoot "dist" - -Write-Host "" -Write-Host "========================================================================" -Write-Host "eBay REST Client - Upload to Forgejo PyPI" -Write-Host "========================================================================" -Write-Host "" - -if (!(Test-Path $python)) { - Write-Host "[!] Virtual environment Python not found at .venv\\Scripts\\python.exe" -ForegroundColor Red - exit 1 -} - -if (!(Test-Path $pypiRcPath)) { - Write-Host "[!] .pypirc not found in project root." -ForegroundColor Red - Write-Host "" - Write-Host "Setup instructions:" - Write-Host " 1. Copy .pypirc.example to .pypirc" - Write-Host " 2. Edit .pypirc and add your Forgejo access token" - Write-Host " 3. Run this script again" - Write-Host "" - Write-Host "For help: .\upload_wheel_to_forgejo_pypi.ps1 -Help" - exit 1 -} - -if (!(Test-Path $buildScript)) { - Write-Host "[!] Build script not found at scripts\\build_wheel.py" -ForegroundColor Red - exit 1 -} - -$null = & $python -c "import importlib.util, sys; sys.exit(0 if importlib.util.find_spec('twine') else 1)" -if ($LASTEXITCODE -ne 0) { - Write-Host "Installing twine..." - & $python -m pip install twine - if ($LASTEXITCODE -ne 0) { - Write-Host "[!] Failed to install twine." -ForegroundColor Red - exit 1 - } -} - -$wheelFiles = @(Get-ChildItem -Path $distPath -Filter "*.whl" -ErrorAction SilentlyContinue) - -if ($Build -or $wheelFiles.Count -eq 0) { - if ($Build) { - Write-Host "Building wheel (forced)..." - } else { - Write-Host "Building wheel..." - } - - $buildArgs = @($buildScript) - if ($Version) { - $buildArgs += "--version" - $buildArgs += $Version - } - - & $python @buildArgs - if ($LASTEXITCODE -ne 0) { - Write-Host "[!] Wheel build failed." -ForegroundColor Red - exit $LASTEXITCODE - } - - $wheelFiles = @(Get-ChildItem -Path $distPath -Filter "*.whl" -ErrorAction Stop) -} - -if ($wheelFiles.Count -eq 0) { - Write-Host "[!] No wheel files found in dist." -ForegroundColor Red - exit 1 -} - -Write-Host "" -Write-Host "========================================================================" -Write-Host "Uploading to Forgejo PyPI..." -Write-Host "========================================================================" -Write-Host "" - -& $python -m twine upload --config-file $pypiRcPath -r forgejo $wheelFiles.FullName -$uploadResult = $LASTEXITCODE - -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 \ No newline at end of file