Skip to main content

Lightweight automation tool designed to streamline the transition from development to distribution.

Project description

pyforge-deploy

License: MIT PyPI - Version PyPI - Downloads GitHub Actions Workflow Status

pyforge-deploy is a lightweight CLI that automates the Python release pipeline.

It simplifies the transition from development → distribution by handling version management, package builds, Docker image creation, PyPI publishing, and CI workflow setup through a single interface.


Why pyforge-deploy?

Publishing Python projects usually involves multiple manual steps:

bump version
build package
upload to PyPI
create Docker image
configure CI workflow

pyforge-deploy automates this workflow so you can release projects consistently and safely.


Features

Automated Release Workflow

Automates the common Python release pipeline:

version → build → publish → docker → CI

Smart Dependency Detection

Automatically detects project dependencies using:

  • AST analysis
  • pyproject.toml
  • requirements.txt

This information is used to generate production-ready Dockerfiles.

Version Management

Safely increments project versions (patch, minor, major) and validates them against the latest version on PyPI to avoid conflicts.

PyPI Deployment

Builds source and wheel distributions and securely publishes them to:

  • PyPI
  • TestPyPI

Docker Integration

Automatically generates a Dockerfile tailored to your project and builds the image using the detected dependencies and Python version.

GitHub Actions Integration

Generate a ready-to-use CI/CD workflow for automated releases with a single command.


Installation

Install from PyPI:

pip install pyforge-deploy

Docker must be installed and running for Docker-related features.


Quickstart

Initialize release automation for your project:

pyforge-deploy init

Build and publish a new release:

pyforge-deploy deploy-pypi --bump patch

Build a Docker image for the project:

pyforge-deploy docker-build

Usage

View all available commands:

pyforge-deploy --help

Initialize GitHub Workflow

Generate a CI/CD workflow file in your repository:

pyforge-deploy init

This creates:

.github/workflows/pyforge-deploy.yml

Build a Docker Image

Automatically detect project dependencies and build an image.

pyforge-deploy docker-build

Specify entry point and image tag:

pyforge-deploy docker-build \
  --entry-point src/pyforge_deploy/cli.py \
  --image-tag my-app:1.0.0

Deploy to PyPI

Build and publish a release.

Bump patch version automatically:

pyforge-deploy deploy-pypi --bump patch

Publish a specific version to TestPyPI:

pyforge-deploy deploy-pypi --version 2.1.0 --test

Inspect Project

View detected dependencies:

pyforge-deploy show-deps

Check current project version:

pyforge-deploy show-version

Configuration

Publishing (OIDC-first)

pyforge-deploy prefers GitHub OIDC (Passwordless / Trusted Publishing) in CI environments: when running inside GitHub Actions with id-token: write permissions, the action can mint short-lived PyPI tokens so you do NOT need to store PYPI_TOKEN as a repository secret. This is the recommended and secure default for automated releases.

Locally (or outside OIDC-capable CI) you may still provide a static token. To use a token locally, set it via a .env file or environment variable:

PYPI_TOKEN=pypi-your-token-here

Use PYPI_TOKEN only for local/manual runs; in CI prefer OIDC/trusted publishing so secrets are not stored long-term.

pyproject.toml configuration

pyforge-deploy reads settings from the [tool.pyforge-deploy] table in pyproject.toml. CLI arguments override values in pyproject.toml, which in turn override environment variables and built-in defaults. Example configuration:

[tool.pyforge-deploy]
default_bump = "patch"          # default bump when releasing
docker_push = true               # whether docker-build should push by default
docker_platforms = "linux/amd64" # platforms for buildx (comma-separated)
auto_confirm = true              # skip interactive prompts
docker_image = "myorg/myapp:latest" # default image tag
docker_python = "3.12"         # override python base image (short form '3.12')
docker_wheelhouse = false        # build a local wheelhouse for Docker builds
docker_non_root = false          # install into non-root user in final image
pypi_retries = 3                 # upload retry attempts
pypi_backoff = 2                 # backoff base seconds for retries

Not all keys are required — the CLI will fall back to sensible defaults when a setting is omitted. See src/pyforge_deploy/builders for how each option is used at runtime.


GitHub Action

pyforge-deploy includes a reusable GitHub Action for automated releases.

After running:

pyforge-deploy init

A workflow file will be generated.

Example workflow (OIDC-enabled template produced by pyforge-deploy init):

name: PyForge Release

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: write
  id-token: write

jobs:
  release:
    name: Build and Publish
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v5
        with:
          fetch-depth: 0

      - name: PyForge Deploy
        uses: ertanturk/pyforge-deploy@main
        with:
          pypi_deploy: 'true'
          docker_build: 'true'
          run_tests: 'true'
          run_security_scan: 'true'
          target_branch: ${{ github.event.repository.default_branch }}
        env:
          DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
          DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}

This template enables GitHub OIDC (id-token: write) so PyPI tokens can be minted dynamically during the workflow. You only need to provide Docker credentials as secrets if you build/push images.


Architecture

The tool is structured into modular components.

VersionEngine

Responsible for resolving and updating project versions.

Sources include:

  • pyproject.toml
  • __about__.py
  • .version_cache

It also fetches the latest version from PyPI to prevent version conflicts.


DockerBuilder

DockerBuilder detects project dependencies and Python version, renders a Dockerfile using a Jinja2 template, and builds the Docker image. It implements several optimizations to produce small, cache-friendly images:

  • Multi-stage builds to keep the final image minimal
  • BuildKit-aware commands and --mount=type=cache usage for pip caching
  • Layer caching via careful ordering of dependency installation
  • Heavy-hitter detection (large packages like numpy, pandas) and separation into heavy-requirements.txt so they can be installed in a dedicated layer for better cache reuse
  • Optional local wheelhouse (wheels/) build to enable --no-index installs and reproducible builds
  • Automatic .dockerignore tuning to reduce build context size

These features make Docker builds faster, more deterministic, and more cache-efficient.


PyPIDistributor

Handles package distribution:

  1. Cleans old build artifacts
  2. Builds source and wheel distributions
  3. Uploads them to PyPI or TestPyPI. When uv is available on the system, the distributor uses uv build and uv publish (ultra-fast) for building and publishing, otherwise it falls back to python -m build and twine upload.

Publishing in CI prefers OIDC-based short-lived tokens; for local/manual runs PYPI_TOKEN is still supported.


License

This project is licensed under the MIT License.

See the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyforge_deploy-0.5.4.tar.gz (52.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyforge_deploy-0.5.4-py3-none-any.whl (44.0 kB view details)

Uploaded Python 3

File details

Details for the file pyforge_deploy-0.5.4.tar.gz.

File metadata

  • Download URL: pyforge_deploy-0.5.4.tar.gz
  • Upload date:
  • Size: 52.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pyforge_deploy-0.5.4.tar.gz
Algorithm Hash digest
SHA256 7f89d5f273c3cef118a7218d627dee73891d38238248f35a2608db8c11458e16
MD5 44b523cb23429000e14c28cd34e2a538
BLAKE2b-256 65ad0acb9e6918e2a6bf43210512910ca9fee51b687c05ff053d9e8a7f5bb836

See more details on using hashes here.

File details

Details for the file pyforge_deploy-0.5.4-py3-none-any.whl.

File metadata

  • Download URL: pyforge_deploy-0.5.4-py3-none-any.whl
  • Upload date:
  • Size: 44.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pyforge_deploy-0.5.4-py3-none-any.whl
Algorithm Hash digest
SHA256 d1b81700954a8c06e94468bc2a2bc55de94c7519b4d4d3330322706766b49cb4
MD5 b0e36e920f8c5074c46315db06c38da6
BLAKE2b-256 50c42fb32b31fd91ac36b50f3a4f0e65bdcca892c8eefd02f24998f71fe445e4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page