From 1df25adc70dc70342ebf3ac8fba9bbe9d9e801c1 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Mon, 7 Sep 2026 20:22:09 +0000 Subject: [PATCH] Add a dry-run mode to PublishOnPyPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both verification pipelines fail on every tag at *⤴ Publish Python wheel package to PyPI* - `_Checking_SimplePackage_Pipeline.yml` and `_Checking_NamespacePackage_Pipeline.yml`, on v7.14.1 and again on v7.15.0. `myPackage` and `myFramework.Extension` are fixtures that exist to exercise the job templates; nobody publishes them. The failure only appears on tags, which is exactly the run someone checks before cutting a release. `PublishOnPyPI.yml` gains a `dry_run` input. When enabled, the two `twine upload` steps are replaced by a single `twine check dist/*.whl dist/*.tar.gz`. Everything before them is unchanged, so the artifact download, the Python setup and the dependency install are still exercised, and the package metadata is validated rather than merely built. `CompletePipeline.yml` forwards it as `pypi_dry_run`, defaulting to `'false'` so no consumer changes behaviour. Skipping the job entirely - an input that drops `PublishOnPyPI` from the pipeline - was the alternative. It would leave the job template unverified, which is what the verification pipelines exist to prevent, so a dry run that still reaches the packages was preferred. Setting `pypi_dry_run: 'true'` in the two verification pipelines is deliberately *not* part of this commit. They call `CompletePipeline.yml@dev`, so an input that exists only on this branch makes GitHub reject the workflow file before a runner is assigned - "This run likely failed because of a workflow file issue". The switch is flipped in a follow-up once this input is on `dev`. Co-Authored-By: Patrick Lehmann --- .github/workflows/CompletePipeline.yml | 6 ++++++ .github/workflows/PublishOnPyPI.yml | 11 ++++++++++ doc/JobTemplate/AllInOne/CompletePipeline.rst | 19 +++++++++++++++++ doc/JobTemplate/Package/PublishOnPyPI.rst | 21 +++++++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/.github/workflows/CompletePipeline.yml b/.github/workflows/CompletePipeline.yml index de40f62a..d0fca361 100644 --- a/.github/workflows/CompletePipeline.yml +++ b/.github/workflows/CompletePipeline.yml @@ -143,6 +143,11 @@ on: required: false default: 'true' type: string + pypi_dry_run: + description: 'Validate the packages with twine, but do not upload them to PyPI.' + required: false + default: 'false' + type: string cleanup: description: 'Cleanup artifacts afterwards.' required: false @@ -537,6 +542,7 @@ jobs: python_version: ${{ needs.UnitTestingParams.outputs.python_version }} requirements: '-r dist/requirements.txt' artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).package_all }} + dry_run: ${{ inputs.pypi_dry_run }} cleanup: ${{ inputs.cleanup }} secrets: PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/PublishOnPyPI.yml b/.github/workflows/PublishOnPyPI.yml index 0411235c..1628f106 100644 --- a/.github/workflows/PublishOnPyPI.yml +++ b/.github/workflows/PublishOnPyPI.yml @@ -44,6 +44,11 @@ on: description: 'Name of the package artifact.' required: true type: string + dry_run: + description: 'Validate the packages with twine, but do not upload them to PyPI.' + required: false + default: 'false' + type: string cleanup: description: 'Cleanup artifacts afterwards.' required: false @@ -74,13 +79,19 @@ jobs: - name: ⚙ Install dependencies for packaging and release run: python -m pip install --disable-pip-version-check ${{ inputs.requirements }} + - name: 🔎 Check Python packages instead of publishing them + if: inputs.dry_run == 'true' + run: twine check dist/*.whl dist/*.tar.gz + - name: ⤴ Publish Python wheel package to PyPI + if: inputs.dry_run != 'true' env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} run: twine upload dist/*.whl - name: ⤴ Publish Python source package to PyPI + if: inputs.dry_run != 'true' env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} diff --git a/doc/JobTemplate/AllInOne/CompletePipeline.rst b/doc/JobTemplate/AllInOne/CompletePipeline.rst index d5e946dd..90d846de 100644 --- a/doc/JobTemplate/AllInOne/CompletePipeline.rst +++ b/doc/JobTemplate/AllInOne/CompletePipeline.rst @@ -471,6 +471,8 @@ Parameter Summary +--------------------------------------------------------------------+----------+--------+----------------------------------------------------------------------------+ | :ref:`JOBTMPL/CompletePipeline/Input/dorny` | no | string | ``'false'`` | +--------------------------------------------------------------------+----------+--------+----------------------------------------------------------------------------+ +| :ref:`JOBTMPL/CompletePipeline/Input/pypi_dry_run` | no | string | ``'false'`` | ++--------------------------------------------------------------------+----------+--------+----------------------------------------------------------------------------+ | :ref:`JOBTMPL/CompletePipeline/Input/cleanup` | no | string | ``'true'`` | +--------------------------------------------------------------------+----------+--------+----------------------------------------------------------------------------+ @@ -932,6 +934,23 @@ auto_tag ``'false'`` - never tag automatically. +.. _JOBTMPL/CompletePipeline/Input/pypi_dry_run: + +pypi_dry_run +============ + +:Type: string +:Required: no +:Default Value: ``'false'`` +:Possible Values: ``'true'`` / ``'false'`` +:Description: Validate the built packages with ``twine check`` instead of uploading them to :term:`PyPI`. + Forwarded to :ref:`JOBTMPL/PublishOnPyPI/Input/dry_run`. |br| + Intended for a pipeline that builds a package which is never published - a fixture used to + exercise the job templates, or a fork that must not push to the upstream project's PyPI name. |br| + ``'true'`` - check the packages and publish nothing. |br| + ``'false'`` - publish the packages. + + .. _JOBTMPL/CompletePipeline/Input/cleanup: cleanup diff --git a/doc/JobTemplate/Package/PublishOnPyPI.rst b/doc/JobTemplate/Package/PublishOnPyPI.rst index af026860..a7ed8bdd 100644 --- a/doc/JobTemplate/Package/PublishOnPyPI.rst +++ b/doc/JobTemplate/Package/PublishOnPyPI.rst @@ -22,6 +22,9 @@ Publish a wheel (``*.whl``) packages and/or source (``*.tar.gz``) package to :te (:ref:`JOBTMPL/PublishOnPyPI/Input/requirements`), which must provide :term:`twine`. 3. Publish the wheel package(s) (:file:`*.whl`). 4. Publish the source package(s) (:file:`*.tar.gz`). + + Steps 3 and 4 are replaced by a ``twine check`` of both package kinds if + :ref:`JOBTMPL/PublishOnPyPI/Input/dry_run` is enabled. 5. Delete the artifact (:ref:`JOBTMPL/PublishOnPyPI/Input/cleanup`). .. topic:: Preconditions @@ -125,6 +128,8 @@ Parameter Summary +---------------------------------------------------------+----------+--------+-------------------+ | :ref:`JOBTMPL/PublishOnPyPI/Input/artifact` | yes | string | — — — — | +---------------------------------------------------------+----------+--------+-------------------+ +| :ref:`JOBTMPL/PublishOnPyPI/Input/dry_run` | no | string | ``'false'`` | ++---------------------------------------------------------+----------+--------+-------------------+ | :ref:`JOBTMPL/PublishOnPyPI/Input/cleanup` | no | string | ``'true'`` | +---------------------------------------------------------+----------+--------+-------------------+ @@ -182,6 +187,22 @@ artifact :Description: Name of the artifact containing the packaged Python package(s). +.. _JOBTMPL/PublishOnPyPI/Input/dry_run: + +dry_run +======= + +:Type: string +:Required: no +:Default Value: ``'false'`` +:Possible Values: ``'true'`` / ``'false'`` +:Description: Validate the packages with ``twine check`` instead of uploading them to :term:`PyPI`. |br| + Everything up to the upload still runs, so the artifact download, the Python setup and the package + metadata are exercised - only the two ``twine upload`` calls are skipped. |br| + ``'true'`` - check the packages and publish nothing. |br| + ``'false'`` - publish the packages. + + .. _JOBTMPL/PublishOnPyPI/Input/cleanup: cleanup