python-project-lifecycle is a composite GitHub Action for common Python project lifecycle phases,
one phase per run. It standardizes step behavior for Python project automation while leaving
workflow topology, permissions, matrices, environments, and deployment approvals in the caller's
workflow.
Build, validate, smoke-test, and upload Python distributions:
- uses: Dagitali/python-project-lifecycle@v0.1.0
with:
phase: build-upload
python-version: '3.13'
release-artifact-audit-command: python tools/check_release_artifacts.py dist/*
behavior-smoke-command: '{python} tools/smoke_test_schema_validation.py {python}'
command-name: my-command
package-name: my-package
smoke-commands: |
my-command --version
my-command --helpBuild Sphinx documentation:
- uses: Dagitali/python-project-lifecycle@v0.1.0
with:
phase: docs
python-version: '3.13'
docs-builder: htmlRun a caller-provided security command:
- uses: Dagitali/python-project-lifecycle@v0.1.0
with:
phase: security
pip-install: 'pip-audit'
security-command: pip-auditThe Required column reflects the action metadata in action.yml. Some inputs with defaults are
still required for specific phases at runtime, as noted in the descriptions below.
| Name | Required | Default | Description |
|---|---|---|---|
phase |
Yes | N/A | Lifecycle phase to run: bootstrap, lint, format-check, test, typecheck, doclint, docs, sbom, security, build, build-upload, upload-dist, download-dist, wheel-smoke, installer-smoke, or deploy. |
python-version |
No | 3.13 |
Python version passed to Dagitali/python-bootstrap, which provisions Python through actions/setup-python. |
pip-install |
No | '' |
Arguments passed to python -m pip install for most bootstrapped phases. Ignored for build, build-upload, docs, upload-dist, and download-dist. |
pip-version |
No | '' |
Exact pip version to install instead of upgrading to latest. |
upgrade-pip |
No | true |
Upgrade pip to latest unless pip-version is set. |
working-directory |
No | . |
Directory where shell commands run. |
ruff-args |
No | check . |
Arguments passed to ruff for the lint phase. |
format-check-command |
No | '' |
Command run by the format-check phase. Required when phase is format-check. |
meta-test-command |
No | '' |
Optional command run before pytest-args in the test phase. |
pytest-args |
No | -q tests/ |
Arguments passed to pytest in the test phase. |
typecheck-command |
No | mypy . |
Command run by the typecheck phase. |
doclint-command |
No | '' |
Command run by the doclint phase. Required when phase is doclint. |
security-command |
No | '' |
Command run by the security phase. Required when phase is security. |
docs-builder |
No | html |
Sphinx builder used by the docs phase. |
docs-source-dir |
No | docs/source |
Sphinx source directory used by the docs phase. The directory must exist. |
docs-build-dir |
No | docs/build |
Sphinx build output root used by the docs phase. |
docs-doctree-dir |
No | docs/build/doctrees |
Sphinx doctree output root used by the docs phase. |
docs-generated-api-dir |
No | docs/source/api/generated |
Existing generated API .rst files deleted before the docs phase. |
docs-pip-install |
No | -e .[docs] |
Dependency install arguments used instead of pip-install for the docs phase. |
build-command |
No | python -m build |
Command used by the build and build-upload phases to build distributions. |
release-artifact-audit-command |
No | '' |
Optional caller-owned command used by build phases to audit release artifacts. |
twine-check |
No | true |
Run python -m twine check during build phases. |
build-pip-install |
No | build twine |
Dependency install arguments used instead of pip-install for build and build-upload. |
skip-installer-smoke |
No | false |
Skip installer smoke tests during build-upload. |
skip-wheel-smoke |
No | false |
Skip wheel behavior smoke tests during build-upload. |
skip-artifact-upload |
No | false |
Skip distribution artifact upload during build-upload. |
dist-glob |
No | dist/* |
Glob or path expression used to select built distributions. |
artifact-name |
No | dist-artifacts |
Artifact name used when uploading or downloading distributions. |
artifact-path |
No | dist |
Destination path for downloaded artifacts. |
sbom-tool-version |
No | 7.2.2 |
CycloneDX tool version installed by the sbom phase. |
sbom-output-file |
No | sbom.json |
SBOM output path. |
sbom-output-format |
No | JSON |
SBOM output format. |
sbom-command |
No | '' |
Optional custom command run by the sbom phase instead of the default generator. |
wheel-glob |
No | dist/*.whl |
Glob or path for the built wheel artifact used by smoke tests. |
smoke-venv-path |
No | .wheel-venv |
Virtual environment path used by wheel-smoke and the delegated pip installer smoke check. |
behavior-smoke-command |
No | '' |
Command run after installing the wheel in wheel-smoke. Use {python} as the smoke-test interpreter placeholder. Required for wheel-smoke and for build-upload unless wheel smoke is skipped. |
command-name |
No | '' |
Command expected to be available on PATH after installing the wheel artifact. Required for installer-smoke and for build-upload unless installer smoke is skipped. |
smoke-commands |
No | '' |
Newline-separated commands passed to the delegated installer smoke action. Required for installer-smoke and for build-upload unless installer smoke is skipped. |
installer-smoke-installers |
No | pip,pipx,uv |
Comma-separated installers to smoke-test. Supported values are pip, pipx, and uv. |
package-name |
No | '' |
Package name passed to installer smoke tests for cleanup when the distribution package name differs from command-name. |
deploy-command |
No | '' |
Command run by the deploy phase. Required when phase is deploy. |
Run linting with Ruff:
- uses: Dagitali/python-project-lifecycle@v0.1.0
with:
phase: lint
python-version: '3.13'
pip-install: ruff
ruff-args: check src testsRun tests with an optional setup command:
- uses: Dagitali/python-project-lifecycle@v0.1.0
with:
phase: test
python-version: '3.13'
pip-install: '-e .[test]'
meta-test-command: python -m compileall src
pytest-args: '-q tests/'Generate an SBOM:
- uses: Dagitali/python-project-lifecycle@v0.1.0
with:
phase: sbom
python-version: '3.13'
sbom-output-file: sbom.jsonDownload distribution artifacts in a later job:
- uses: Dagitali/python-project-lifecycle@v0.1.0
with:
phase: download-dist
artifact-name: dist-artifacts
artifact-path: distDeploy with a caller-owned command:
- uses: Dagitali/python-project-lifecycle@v0.1.0
with:
phase: deploy
deploy-command: python tools/deploy.pySet phase to select exactly one lifecycle operation:
| Phase | Behavior |
|---|---|
bootstrap |
Installs the requested Python version and pip dependencies, then captures Python and pip output metadata. |
lint |
Bootstraps Python, prints the Ruff version, and runs ruff with ruff-args. |
format-check |
Bootstraps Python and runs format-check-command. |
test |
Bootstraps Python, optionally runs meta-test-command, then runs pytest with pytest-args. |
typecheck |
Bootstraps Python and runs typecheck-command. |
doclint |
Bootstraps Python and runs doclint-command. |
docs |
Bootstraps Python with docs-pip-install, removes stale generated API .rst files when present, clears the selected builder output and doctree directories, and runs Sphinx with warnings treated as errors. |
sbom |
Bootstraps Python and generates an environment SBOM with cyclonedx-py, or runs sbom-command when provided. The default generator currently uses POSIX virtual environment paths; use sbom-command for Windows runners. |
security |
Bootstraps Python and runs security-command. |
build |
Bootstraps Python with build-pip-install, runs build-command, optionally runs release-artifact-audit-command, then optionally runs python -m twine check against dist-glob. |
build-upload |
Runs the build behavior, then wheel smoke tests, installer smoke tests, and artifact upload unless the corresponding skip inputs are set. |
upload-dist |
Uploads dist-glob as artifact-name without bootstrapping Python. |
download-dist |
Downloads artifact-name to artifact-path without bootstrapping Python. |
wheel-smoke |
Creates a temporary virtual environment, installs the selected wheel, and runs behavior-smoke-command. |
installer-smoke |
Delegates installer validation to Dagitali/python-installer-smoke, testing the selected wheel with pip, pipx, and/or uv. |
deploy |
Bootstraps Python and runs deploy-command. |
Most command-valued inputs are executed as trusted shell snippets in the configured
working-directory. smoke-commands is passed through to the delegated
Dagitali/python-installer-smoke action rather than run directly by this action. Empty command
inputs are rejected for phases that require a caller-provided command.
The skip-artifact-upload, skip-installer-smoke, and skip-wheel-smoke inputs are validated on
every run and must be exactly true or false. The twine-check input must be exactly true or
false for build and build-upload.
The action composes pinned public actions for Python bootstrapping, installer smoke testing,
artifact upload, and artifact download. It also uses helper scripts in scripts/ through
GITHUB_ACTION_PATH.
Treat all command inputs, path and glob inputs, dependency install arguments, and smoke-test command inputs as trusted workflow configuration. Do not build these values from untrusted issue, pull request, or user-supplied text.
The command inputs are shell commands. Keep smoke and validation commands small and deterministic,
such as --version, --help, import checks, metadata checks, or lightweight startup behavior
checks.
This action pins the public actions it composes by commit SHA. Calling workflows should still pin this action to a release tag or full commit SHA.
Outputs mostly mirror the configured paths. upload-dist and download-dist do not bootstrap
Python, so python-version and pip-version reflect whatever Python is already available on the
runner, or an empty value if none is found.
| Name | Description |
|---|---|
python-version |
Resolved Python version reported by python --version. |
pip-version |
Resolved pip version reported by python -m pip --version. |
dist-path |
Distribution artifact path or glob used for upload and validation. |
artifact-path |
Destination path used when downloading distribution artifacts. |
artifact-name |
Uploaded or downloaded artifact name. |
wheel-path |
Wheel artifact path or glob used by smoke tests. |
docs-output-dir |
Built documentation output directory. |
sbom-path |
Generated SBOM path. |
coverage-file |
Conventional coverage report path, coverage.xml. The action exposes this path but does not generate coverage by itself. |
The action itself does not require repository or token permissions. Calling workflows should grant
only the permissions needed by their own jobs, such as contents: read for checkout, package
publishing permissions, or deployment environment permissions.
Prefer a release tag such as Dagitali/python-project-lifecycle@v0.1.0 or an exact version tag for
normal use. Pin to a full commit SHA when your workflow requires maximum supply-chain immutability.
Copyright © 2026 Dagitali LLC. All rights reserved.
See LICENSE for details.