Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
name: Python publish to PyPI (reusable)
name: Python verify and build for PyPI (reusable)

# Bezpečná publikace přes PyPI Trusted Publishing (OIDC), bez API tokenů.
# Volající workflow MUSÍ mít soubor .github/workflows/publish.yml - PyPI Trusted Publisher
# se registruje na název volajícího workflow, ne tohoto.
# Volání: uses: SYSNET-CZ/.github/.github/workflows/python-publish.yml@v1
# Ověření release tagu/verze a build distribuce pro publikaci na PyPI. Samotný upload NEDĚLÁ:
# PyPI oficiálně nepodporuje reusable workflow jako Trusted Publisher, proto upload
# (pypa/gh-action-pypi-publish s id-token: write) patří přímo do volajícího publish.yml,
# který si artefakt "python-dist" stáhne. Viz docs/pypi-trusted-publishing.md.
# Volání: uses: SYSNET-CZ/.github/.github/workflows/[email protected]

on:
workflow_call:
Expand All @@ -15,10 +16,6 @@ on:
python-version:
type: string
default: '3.12'
environment:
description: 'GitHub environment publikačního jobu'
type: string
default: 'pypi'
repository-url:
description: 'Prázdné = produkční PyPI; https://test.pypi.org/legacy/ = TestPyPI'
type: string
Expand All @@ -27,10 +24,6 @@ on:
description: 'Větev, ze které smí release tag pocházet'
type: string
default: 'main'
dry-run:
description: 'Pouze ověření a build, bez publikace'
type: boolean
default: false
outputs:
version:
description: 'Publikovaná verze'
Expand Down Expand Up @@ -153,25 +146,3 @@ jobs:
path: dist/
if-no-files-found: error
retention-days: 7

publish:
name: Publish to PyPI
needs: verify
if: ${{ !inputs.dry-run }}
runs-on: ubuntu-latest
environment:
name: ${{ inputs.environment }}
url: ${{ inputs.repository-url == '' && format('https://pypi.org/project/{0}/{1}/', inputs.package-name, needs.verify.outputs.version) || '' }}
permissions:
contents: read
id-token: write # OIDC pro Trusted Publishing
steps:
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: python-dist
path: dist/
- uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
with:
repository-url: ${{ inputs.repository-url }}
packages-dir: dist/
attestations: false # pro privátní repozitáře nejsou podporovány
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ Všechny šablony jsou přednastaveny na **self-hosted runner** (`hermes-vm`).
| Workflow | Účel |
|---|---|
| `python-ci.yml` | lint, testy v matici verzí, build a `twine check` |
| `python-publish.yml` | ověření tagu/verze, publikace na PyPI přes OIDC (Trusted Publishing) |
| `python-build.yml` | ověření tagu/verze/názvu, build a `twine check`; upload dělá volající workflow (OIDC) |
| `python-release.yml` | GitHub Release z `CHANGELOG.md` |

Volat přes přesný tag (`@v1.1.0`). Dokumentace: [`docs/python-packaging.md`](docs/python-packaging.md),
Volat přes přesný tag (`@v1.2.0`). Dokumentace: [`docs/python-packaging.md`](docs/python-packaging.md),
[`docs/python-release-process.md`](docs/python-release-process.md),
[`docs/pypi-trusted-publishing.md`](docs/pypi-trusted-publishing.md).
15 changes: 11 additions & 4 deletions docs/pypi-trusted-publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Existující projekt: PyPI -> projekt -> **Manage** -> **Publishing** -> *Add a
| PyPI project name | např. `sysnet-pyutils` |
| Owner | `SYSNET-CZ` |
| Repository name | např. `pyutils` |
| Workflow name | `publish.yml` (**název volajícího workflow**, ne `python-publish.yml`) |
| Workflow name | `publish.yml` (**volající workflow s krokem uploadu**) |
| Environment name | `pypi` |

Nový projekt: stejná tabulka v **Your account -> Publishing** jako *Pending Publisher*; projekt vznikne prvním
Expand Down Expand Up @@ -44,12 +44,19 @@ při publikaci. Pro privátní repozitáře se attestations nevytvářejí (`att
- Po zprovoznění Trusted Publishingu smazat secret `PYPI_API_TOKEN` (repo i org) a token na PyPI zneplatnit.
- Odchod člena týmu: odebrat z PyPI projektů a z GitHub týmů s právem push na tagy.

## TestPyPI (od `v1.1.0`)
## Upload musí být ve volajícím workflow

`python-publish.yml` s `repository-url: https://test.pypi.org/legacy/` běží v testovacím režimu: nevyžaduje tag ani
Pokus o upload z reusable workflow (`v1.1.0`) selhal na `invalid-publisher`, ačkoli publisher odpovídal volajícímu
workflow. PyPI reusable workflow jako publishera oficiálně nepodporuje (warehouse#11096). Proto `python-build.yml`
(od `v1.2.0`) jen ověřuje a sestavuje a krok `pypa/gh-action-pypi-publish` je přímo v `publish.yml` knihovny.
Ověřeno úspěšným uploadem dev verze na TestPyPI.

## TestPyPI

`python-build.yml` s `repository-url: https://test.pypi.org/legacy/` běží v testovacím režimu: nevyžaduje tag ani
větev `main`, ale **přijme jen dev verze** (`X.Y.Z.devN`), takže produkční číslo verze nelze touto cestou spálit.
Doporučené spouštění: `workflow_dispatch` ve vlastním `publish-test.yml` s environmentem `testpypi`.

## Verze reusable workflows

Odkazujte přesným tagem (`@v1.1.0`); existující tagy se nepřepisují, ani pohyblivý `v1` (zůstává na `v1.0.0`).
Odkazujte přesným tagem (`@v1.2.0`); existující tagy se nepřepisují, ani pohyblivý `v1` (zůstává na `v1.0.0`); `v1.0.0` a `v1.1.0` obsahují nepoužitelný `python-publish.yml`.
31 changes: 24 additions & 7 deletions docs/python-packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,14 @@ jobs:
ci:
permissions:
contents: read
uses: SYSNET-CZ/.github/.github/workflows/python-ci.yml@v1.1.0
uses: SYSNET-CZ/.github/.github/workflows/python-ci.yml@v1.2.0
with:
python-versions: '["3.11", "3.12", "3.13"]'
```

`.github/workflows/publish.yml` - **název souboru musí být přesně `publish.yml`**, na něj se registruje Trusted Publisher:
`.github/workflows/publish.yml` - **název souboru musí být přesně `publish.yml`**, na něj se registruje Trusted Publisher.
Upload na PyPI musí být přímo v něm (PyPI oficiálně nepodporuje reusable workflow jako publishera, ověřeno
`invalid-publisher` při pokusu o upload z reusable workflow); ověření a build je centrální:

```yaml
name: Publish
Expand All @@ -73,23 +75,38 @@ concurrency:
group: publish-${{ github.ref }}
cancel-in-progress: false
jobs:
publish:
build:
permissions:
contents: read
id-token: write
uses: SYSNET-CZ/.github/.github/workflows/[email protected]
uses: SYSNET-CZ/.github/.github/workflows/[email protected]
with:
package-name: sysnet-priklad
publish:
needs: build
runs-on: ubuntu-latest
environment: pypi
permissions:
contents: read
id-token: write
steps:
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: python-dist
path: dist/
- uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
with:
packages-dir: dist/
attestations: false
release:
needs: publish
permissions:
contents: write
uses: SYSNET-CZ/.github/.github/workflows/python-release.yml@v1.1.0
uses: SYSNET-CZ/.github/.github/workflows/python-release.yml@v1.2.0
with:
package-name: sysnet-priklad
```

Volejte vždy přes přesný verzovaný tag (`@v1.1.0`), nikdy `@main`. Tagy se nepřepisují, každá změna reusable workflow je nový tag `v1.x.y`.
Volejte vždy přes přesný verzovaný tag (`@v1.2.0`), nikdy `@main`. Tagy se nepřepisují, každá změna reusable workflow je nový tag `v1.x.y`.

## 4. Runnery

Expand Down
4 changes: 2 additions & 2 deletions tests/test_publish_checks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Tests of the version/name verification embedded in python-publish.yml.
"""Tests of the version/name verification embedded in python-build.yml.

Extracts the inline Python of the "Verify distribution" step, builds a tiny fixture
package and runs the step with valid and invalid tags/names.
Expand All @@ -13,7 +13,7 @@
import pytest
import yaml

WORKFLOW = Path(__file__).parent.parent / ".github/workflows/python-publish.yml"
WORKFLOW = Path(__file__).parent.parent / ".github/workflows/python-build.yml"


def _step_script() -> str:
Expand Down
Loading