Opinionated GitHub action to fully automate publishing packages to PyPI - using Poetry and GitHub releases.
We published this action because we use it in our projects and thought it would be useful to others as well. This action is open to any kind of collaboration and contribution - We're happy to receive feedback, issues, pull requests or just kudos.
main, master, beta, etc.Jump to example: - Publish to public PyPI - With private dependencies - To a private PyPI - With private dependencies
This action assumes you use poetry as your package manager and have the pyproject.toml and poetry.lock files in the root directory of your
repository.
my_project/
├─ example_package/
│ ├─ __init__.py
├─ pyproject.toml
├─ poetry.lock
If you do not use a custom runner, you may use the builtin functionality
GITHUB_TOKENwith write permissions as theACCESS_TOKENas seen in the first example. See [https://docs.github.com/en/actions/security-guides/automatic-token-authentication#using-the-github_token-in-a-workflow](https://docs.github. com/en/actions/security-guides/automatic-token-authentication#using-the-github_token-in-a-workflow)
️ We recommend you to use this workflow with the test PyPI registry e.g.PUBLISH_REGISTRY: "https://test.pypi.org/simple/"until you can confirm your workflow works as expected.
name: Build and publish python package
on:
release:
types: [ published ]
jobs:
publish-service-client-package:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Publish PyPi package
uses: code-specialist/pypi-poetry-publish@v1
with:
ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PUBLISH_REGISTRY_PASSWORD: ${{ secrets.PYPI_TOKEN }}1.0.0 (Trigger)pyproject.toml and __init__.py in the package directory according to the tag./pyproject.toml
[tool.poetry]
name = "code-specialist-example-package"
version = "0.1.0"
description = "Example package"
authors = ["Code Specialist"]
packages = [{include = "example_package"}]
[tool.poetry.dependencies]
python = "^3.10"./example_package/init.py
__version__ = "0.1.0"The action will alter the content of your repository to avoid conflicts and version mismatches:
pyproject.toml
[tool.poetry]
name = "code-specialist-example-package"
version = "1.0.0" # adjusted to 1.0.0
description = "Example package"
authors = ["Code Specialist"]
packages = [{include = "example_package"}]
[tool.poetry.dependencies]
python = "^3.10"./example_package/init.py
__version__ = "1.0.0" # adjusted to 1.0.0The inputs marked with (✓) are required if the
POETRY_DEPENDENCY_REGISTRY_URLis set.
| Name | Description | Mandatory | Default |
|---|---|---|---|
ACCESS_TOKEN |
GitHub token with write access to the repository, to adjust the version | ✓ | |
PUBLISH_REGISTRY_PASSWORD |
Either a password for the registry user or a token in combination with __token__ as the PUBLISH_REGISTRY_USERNAME |
✓ | |
PUBLISH_REGISTRY_USERNAME |
The username for the pypi registry | __token__ |
|
PACKAGE_DIRECTORY |
The directory the package is located in e.g. ./src/, ./example_package |
'./' | |
POETRY_VERSION |
The Poetry version to perform the build with | 1.1.8 |
|
POETRY_CORE_VERSION |
The Poetry Code version to perform the build with | 1.0.4 |
|
PYTHON_VERSION |
The Python version to perform the build with | 3.10 |
|
BRANCH |
The branch to publish from | master |
|
PUBLISH_REGISTRY |
The registry to publish to e.g.https://test.pypi.org/simple/ |
https://pypi.org/simple/ |
|
POETRY_DEPENDENCY_REGISTRY_URL |
Allows to define a custom registry to be used by Poetry for dependency installation e.g. https://pypi.code-specialist.com/simple/ |
||
POETRY_DEPENDENCY_REGISTRY_NAME |
The name used for the custom registry in the dependencies. Must match the name in the pyproject.toml |
(✓) | |
POETRY_DEPENDENCY_REGISTRY_USERNAME |
The username for the custom registry | (✓) | |
POETRY_DEPENDENCY_REGISTRY_PASSWORD |
The password for the custom registry | (✓) | |
POETRY_CUSTOM_REGISTRY_AUTH |
The authentication type for the custom registry | http-basic |
Each example requires you to:
.github/workflows/publish.yaml1.0.0 and the action will be triggered and publishes your packageIf there is a use case you would like to see, please open an issue or a pull request.
PUBLISH_REGISTRY_PASSWORD with a valid tokenIn order to use the GITHUB_TOKEN you also have to provide permissions for the token. In this case you require the contents:write permission.
publish.yaml
name: Build and publish python package
on:
release:
types: [ published ]
jobs:
publish-service-client-package:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Publish PyPi package
uses: code-specialist/pypi-poetry-publish@v1
with:
PACKAGE_DIRECTORY: "./example-package/"
PYTHON_VERSION: "3.10"
ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PUBLISH_REGISTRY_PASSWORD: ${{ secrets.PUBLISH_REGISTRY_PASSWORD }}PUBLISH_REGISTRY_PASSWORD with a valid tokenACCESS_TOKEN access token with write access to the GitHub repositorypublish.yaml
name: Build and publish python package
on:
release:
types: [ published ]
jobs:
publish-service-client-package:
runs-on: ubuntu-latest
steps:
- name: Publish PyPi package
uses: code-specialist/pypi-poetry-publish@v1
with:
PACKAGE_DIRECTORY: "./example-package/"
PYTHON_VERSION: "3.10"
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
PUBLISH_REGISTRY_PASSWORD: ${{ secrets.PUBLISH_REGISTRY_PASSWORD }}
PUBLISH_REGISTRY: "https://test.pypi.org/legacy/"PUBLISH_REGISTRY_USER username for the PyPI registryPUBLISH_REGISTRY_PASSWORD with the password for the PUBLISH_REGISTRY_USER userACCESS_TOKEN access token with write access to the GitHub repositorypublish.yaml
name: Build and publish python package
on:
release:
types: [ published ]
jobs:
publish-service-client-package:
runs-on: ubuntu-latest
steps:
- name: Publish PyPI package
uses: code-specialist/pypi-poetry-publish@v1
with:
PACKAGE_DIRECTORY: "./example-package/"
PYTHON_VERSION: "3.10"
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
PUBLISH_REGISTRY_PASSWORD: ${{ secrets.PUBLISH_REGISTRY_PASSWORD }}
PUBLISH_REGISTRY_USER: ${{ secrets.PUBLISH_REGISTRY_USER }}
PUBLISH_REGISTRY: "https://pypi.code-specialist.com/simple/"ACCESS_TOKEN access token with write access to the GitHub repositoryPUBLISH_REGISTRY_USER username for the PyPI registryPUBLISH_REGISTRY_PASSWORD with the password for the PUBLISH_REGISTRY_USER userPOETRY_DEPENDENCY_REGISTRY_USERNAME username for the custom registryPOETRY_DEPENDENCY_REGISTRY_PASSWORD password for the custom registrypublish.yaml
name: Build and publish python package
on:
release:
types: [ published ]
jobs:
publish-service-client-package:
runs-on: ubuntu-latest
steps:
- name: Publish PyPI package
uses: code-specialist/pypi-poetry-publish@v1
with:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
PUBLISH_REGISTRY_USER: ${{ secrets.PUBLISH_REGISTRY_USER }}
PUBLISH_REGISTRY_PASSWORD: ${{ secrets.PUBLISH_REGISTRY_PASSWORD }}
PUBLISH_REGISTRY: "https://pypi.code-specialist.com"
POETRY_DEPENDENCY_REGISTRY_URL: "https://pypi.code-specialist.com"
POETRY_DEPENDENCY_REGISTRY_NAME: "codespecialist"
POETRY_DEPENDENCY_REGISTRY_USERNAME: ${{ secrets.CUSTOM_PUBLISH_REGISTRY_USERNAME }}
POETRY_DEPENDENCY_REGISTRY_PASSWORD: ${{ secrets.CUSTOM_PUBLISH_REGISTRY_PASSWORD }} For this to install the dependency private-code-specialist-example-package from https://pypi.code-specialist.com/simple/, the corresponding pyproject.toml would look like
this:
[tool.poetry]
name = "code-specialist-example-package"
version = "1.0.0" # adjusted to 1.0.0
description = "Example package"
authors = ["Code Specialist"]
packages = [{include = "example_package"}]
[[tool.poetry.source]]
name = "codespecialist"
url = "https://pypi.code-specialist.com"
[tool.poetry.dependencies]
python = "^3.10"
private-code-specialist-example-package = {version = "^1.0.0", source = "codespecialist"}