From 010e39d57af203d1237a507b6f3887a83cc437e6 Mon Sep 17 00:00:00 2001 From: Copilot Date: Mon, 27 Jul 2026 14:22:39 -0400 Subject: [PATCH 1/8] DEVOPS-1154 update workflow refs and PyPI publish flow --- .../workflows/reusable-python-publish_pypi_package.yml | 8 -------- .github/workflows/reusable-python-release_pypi_assets.yml | 8 -------- 2 files changed, 16 deletions(-) diff --git a/.github/workflows/reusable-python-publish_pypi_package.yml b/.github/workflows/reusable-python-publish_pypi_package.yml index 82bb7c0..13b4563 100644 --- a/.github/workflows/reusable-python-publish_pypi_package.yml +++ b/.github/workflows/reusable-python-publish_pypi_package.yml @@ -139,14 +139,6 @@ jobs: artifactory-dir-path: ${{ matrix.virtual-repo-name }}/${{ inputs.package-name }}/${{ env.version }} JFROG_ARTIFACTORY_URL: ${{ secrets.JFROG_ARTIFACTORY_URL }} JFROG_ARTIFACTORY_TOKEN: ${{ secrets.JFROG_ARTIFACTORY_TOKEN }} - - name: Publish package to PyPI - if: ${{ matrix.virtual-repo-name == 'pypi' || matrix.virtual-repo-name == 'test-pypi'}} - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1 - with: - verbose: true - packages-dir: ${{ env.build-dir-path }}/ - repository-url: https://${{ matrix.virtual-repo-name == 'test-pypi' && 'test.pypi' || 'upload.pypi'}}.org/legacy/ - password: ${{ secrets.PYPI_TOKEN }} add_release_asset: name: Add release asset diff --git a/.github/workflows/reusable-python-release_pypi_assets.yml b/.github/workflows/reusable-python-release_pypi_assets.yml index ef9d77d..5e3da7a 100644 --- a/.github/workflows/reusable-python-release_pypi_assets.yml +++ b/.github/workflows/reusable-python-release_pypi_assets.yml @@ -69,11 +69,3 @@ jobs: artifactory-dir-path: ${{ matrix.virtual-repo-name }}/${{ inputs.package-name }}/${{ inputs.release-tag }} JFROG_ARTIFACTORY_URL: ${{ secrets.JFROG_ARTIFACTORY_URL }} JFROG_ARTIFACTORY_TOKEN: ${{ secrets.JFROG_ARTIFACTORY_TOKEN }} - - name: Publish package to PyPI - if: ${{ matrix.virtual-repo-name == 'pypi' || matrix.virtual-repo-name == 'test-pypi'}} - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1 - with: - verbose: true - packages-dir: download-assets/ - repository-url: https://${{ matrix.virtual-repo-name == 'test-pypi' && 'test.pypi' || 'upload.pypi'}}.org/legacy/ - password: ${{ secrets.PYPI_TOKEN }} From e43936e01a1ef05ee1a3a632a80ac2410e61ebeb Mon Sep 17 00:00:00 2001 From: Copilot Date: Wed, 29 Jul 2026 09:52:59 -0400 Subject: [PATCH 2/8] Updating code by using an action, for more reusability. --- .../action.yml | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/actions/reusable-python-publish_to_pypi/action.yml diff --git a/.github/actions/reusable-python-publish_to_pypi/action.yml b/.github/actions/reusable-python-publish_to_pypi/action.yml new file mode 100644 index 0000000..257cdf2 --- /dev/null +++ b/.github/actions/reusable-python-publish_to_pypi/action.yml @@ -0,0 +1,70 @@ +name: Publish to PyPI (trusted publishing) +description: > + Download built distribution files (from a workflow artifact or a GitHub + release) and publish them to PyPI/TestPyPI using OIDC trusted publishing. + Must be invoked as a step in a job defined directly in the caller's own + top-level workflow file (not from within a reusable *workflow*), so the + OIDC token's workflow_ref matches the repository's configured PyPI + trusted publisher. +inputs: + source: + description: 'Where to fetch the built packages from: "artifact" or "release"' + required: true + type: string + artifact-name: + description: 'Name of the workflow artifact to download. Required when source is "artifact"' + required: false + type: string + default: '' + release-tag: + description: 'Tag of the GitHub release to download assets from. Required when source is "release"' + required: false + type: string + default: '' + github-token: + description: 'Token used to download release assets via "gh release download". Required when source is "release"' + required: false + type: string + default: '' + repository-url: + description: PyPI-compatible upload endpoint + required: true + type: string + verbose: + description: Enable verbose output on the publish step + required: false + type: string + default: 'true' + attestations: + description: Generate and upload PEP 740 attestations + required: false + type: string + default: 'true' + +runs: + using: composite + steps: + - name: Download build artifact + if: ${{ inputs.source == 'artifact' }} + uses: actions/download-artifact@v8 + with: + name: ${{ inputs.artifact-name }} + path: dist-download + - name: Download release assets + if: ${{ inputs.source == 'release' }} + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.github-token }} + GH_REPO: ${{ github.repository }} + INPUTS_RELEASE_TAG: ${{ inputs.release-tag }} + run: | + mkdir -p dist-download + cd dist-download + gh release download "${INPUTS_RELEASE_TAG}" -p '*.tar.gz' -p '*.whl' + - name: Publish package + uses: pypa/gh-action-pypi-publish@v1.14.1 + with: + verbose: ${{ inputs.verbose }} + packages-dir: dist-download/ + repository-url: ${{ inputs.repository-url }} + attestations: ${{ inputs.attestations }} From 8297982f382a84f27702cb10301abd12c689f77e Mon Sep 17 00:00:00 2001 From: Copilot Date: Wed, 29 Jul 2026 10:01:47 -0400 Subject: [PATCH 3/8] test commit --- .github/actions/reusable-python-publish_to_pypi/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/reusable-python-publish_to_pypi/action.yml b/.github/actions/reusable-python-publish_to_pypi/action.yml index 257cdf2..7339183 100644 --- a/.github/actions/reusable-python-publish_to_pypi/action.yml +++ b/.github/actions/reusable-python-publish_to_pypi/action.yml @@ -5,7 +5,7 @@ description: > Must be invoked as a step in a job defined directly in the caller's own top-level workflow file (not from within a reusable *workflow*), so the OIDC token's workflow_ref matches the repository's configured PyPI - trusted publisher. + trusted publisher. inputs: source: description: 'Where to fetch the built packages from: "artifact" or "release"' From fddd74efdf5d218d6380f730cfce4262e1d60ad0 Mon Sep 17 00:00:00 2001 From: Romain Floreani Date: Wed, 29 Jul 2026 10:10:05 -0400 Subject: [PATCH 4/8] testing the new commit --- .github/actions/reusable-python-publish_to_pypi/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/reusable-python-publish_to_pypi/action.yml b/.github/actions/reusable-python-publish_to_pypi/action.yml index 7339183..257cdf2 100644 --- a/.github/actions/reusable-python-publish_to_pypi/action.yml +++ b/.github/actions/reusable-python-publish_to_pypi/action.yml @@ -5,7 +5,7 @@ description: > Must be invoked as a step in a job defined directly in the caller's own top-level workflow file (not from within a reusable *workflow*), so the OIDC token's workflow_ref matches the repository's configured PyPI - trusted publisher. + trusted publisher. inputs: source: description: 'Where to fetch the built packages from: "artifact" or "release"' From 3feab8080a025e15e36d37479b2cc714c4d43bcf Mon Sep 17 00:00:00 2001 From: Romain Floreani Date: Mon, 17 Aug 2026 09:52:53 -0400 Subject: [PATCH 5/8] New test to fix error --- .../action.yml | 32 +++---------------- 1 file changed, 5 insertions(+), 27 deletions(-) rename .github/actions/{reusable-python-publish_to_pypi => reusable-python-download_dist}/action.yml (59%) diff --git a/.github/actions/reusable-python-publish_to_pypi/action.yml b/.github/actions/reusable-python-download_dist/action.yml similarity index 59% rename from .github/actions/reusable-python-publish_to_pypi/action.yml rename to .github/actions/reusable-python-download_dist/action.yml index 257cdf2..0adaded 100644 --- a/.github/actions/reusable-python-publish_to_pypi/action.yml +++ b/.github/actions/reusable-python-download_dist/action.yml @@ -1,11 +1,10 @@ -name: Publish to PyPI (trusted publishing) +name: Download Python distribution files description: > Download built distribution files (from a workflow artifact or a GitHub - release) and publish them to PyPI/TestPyPI using OIDC trusted publishing. - Must be invoked as a step in a job defined directly in the caller's own - top-level workflow file (not from within a reusable *workflow*), so the - OIDC token's workflow_ref matches the repository's configured PyPI - trusted publisher. + release) to a local "dist-download" directory, ready to be published + (e.g. with pypa/gh-action-pypi-publish). This is a plain composite + action (no self-resolving docker step), so it is safe to call from + another composite action or from a caller's top-level workflow. inputs: source: description: 'Where to fetch the built packages from: "artifact" or "release"' @@ -26,20 +25,6 @@ inputs: required: false type: string default: '' - repository-url: - description: PyPI-compatible upload endpoint - required: true - type: string - verbose: - description: Enable verbose output on the publish step - required: false - type: string - default: 'true' - attestations: - description: Generate and upload PEP 740 attestations - required: false - type: string - default: 'true' runs: using: composite @@ -61,10 +46,3 @@ runs: mkdir -p dist-download cd dist-download gh release download "${INPUTS_RELEASE_TAG}" -p '*.tar.gz' -p '*.whl' - - name: Publish package - uses: pypa/gh-action-pypi-publish@v1.14.1 - with: - verbose: ${{ inputs.verbose }} - packages-dir: dist-download/ - repository-url: ${{ inputs.repository-url }} - attestations: ${{ inputs.attestations }} From 70f01613d73688ce02a4aa662804f74569642721 Mon Sep 17 00:00:00 2001 From: Romain Floreani Date: Wed, 26 Aug 2026 07:03:59 -0400 Subject: [PATCH 6/8] Refactor for PR comments --- .../reusable-python-download_dist/action.yml | 48 ------------------- .../action.yml | 18 +++++++ .../action.yml | 27 +++++++++++ .../reusable-python-publish_pypi_package.yml | 8 +++- .../reusable-python-release_pypi_assets.yml | 8 +++- 5 files changed, 58 insertions(+), 51 deletions(-) delete mode 100644 .github/actions/reusable-python-download_dist/action.yml create mode 100644 .github/actions/reusable-python-download_dist_artifact/action.yml create mode 100644 .github/actions/reusable-python-download_dist_release/action.yml diff --git a/.github/actions/reusable-python-download_dist/action.yml b/.github/actions/reusable-python-download_dist/action.yml deleted file mode 100644 index 0adaded..0000000 --- a/.github/actions/reusable-python-download_dist/action.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Download Python distribution files -description: > - Download built distribution files (from a workflow artifact or a GitHub - release) to a local "dist-download" directory, ready to be published - (e.g. with pypa/gh-action-pypi-publish). This is a plain composite - action (no self-resolving docker step), so it is safe to call from - another composite action or from a caller's top-level workflow. -inputs: - source: - description: 'Where to fetch the built packages from: "artifact" or "release"' - required: true - type: string - artifact-name: - description: 'Name of the workflow artifact to download. Required when source is "artifact"' - required: false - type: string - default: '' - release-tag: - description: 'Tag of the GitHub release to download assets from. Required when source is "release"' - required: false - type: string - default: '' - github-token: - description: 'Token used to download release assets via "gh release download". Required when source is "release"' - required: false - type: string - default: '' - -runs: - using: composite - steps: - - name: Download build artifact - if: ${{ inputs.source == 'artifact' }} - uses: actions/download-artifact@v8 - with: - name: ${{ inputs.artifact-name }} - path: dist-download - - name: Download release assets - if: ${{ inputs.source == 'release' }} - shell: bash - env: - GITHUB_TOKEN: ${{ inputs.github-token }} - GH_REPO: ${{ github.repository }} - INPUTS_RELEASE_TAG: ${{ inputs.release-tag }} - run: | - mkdir -p dist-download - cd dist-download - gh release download "${INPUTS_RELEASE_TAG}" -p '*.tar.gz' -p '*.whl' diff --git a/.github/actions/reusable-python-download_dist_artifact/action.yml b/.github/actions/reusable-python-download_dist_artifact/action.yml new file mode 100644 index 0000000..804bcaf --- /dev/null +++ b/.github/actions/reusable-python-download_dist_artifact/action.yml @@ -0,0 +1,18 @@ +name: Download Python distribution files (workflow artifact) +description: > + Download built distribution files from a workflow artifact into a local + "dist-download" directory, ready to be published. +inputs: + artifact-name: + description: Name of the workflow artifact to download + required: true + type: string + +runs: + using: composite + steps: + - name: Download build artifact + uses: actions/download-artifact@v8 + with: + name: ${{ inputs.artifact-name }} + path: dist-download diff --git a/.github/actions/reusable-python-download_dist_release/action.yml b/.github/actions/reusable-python-download_dist_release/action.yml new file mode 100644 index 0000000..06de400 --- /dev/null +++ b/.github/actions/reusable-python-download_dist_release/action.yml @@ -0,0 +1,27 @@ +name: Download Python distribution files (GitHub release) +description: > + Download built distribution files from a GitHub release into a local + "dist-download" directory, ready to be published. +inputs: + release-tag: + description: Tag of the GitHub release to download assets from + required: true + type: string + github-token: + description: Token used to download release assets via "gh release download" + required: true + type: string + +runs: + using: composite + steps: + - name: Download release assets + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.github-token }} + GH_REPO: ${{ github.repository }} + INPUTS_RELEASE_TAG: ${{ inputs.release-tag }} + run: | + mkdir -p dist-download + cd dist-download + gh release download "${INPUTS_RELEASE_TAG}" -p '*.tar.gz' -p '*.whl' diff --git a/.github/workflows/reusable-python-publish_pypi_package.yml b/.github/workflows/reusable-python-publish_pypi_package.yml index 13b4563..06c3b96 100644 --- a/.github/workflows/reusable-python-publish_pypi_package.yml +++ b/.github/workflows/reusable-python-publish_pypi_package.yml @@ -22,7 +22,9 @@ on: type: boolean default: true virtual-repo-names: - description: 'List of virtual repository names to publish to (e.g. ["public-pypi-dev", "geophysics-pypi-dev"])' + description: > + List of virtual repository names to publish to (e.g. ["public-pypi-dev", "geophysics-pypi-dev"]). + "pypi"/"test-pypi" are a deliberate no-op here; PyPI publishing runs in the caller (DEVOPS-1154). required: true type: string os: @@ -139,6 +141,10 @@ jobs: artifactory-dir-path: ${{ matrix.virtual-repo-name }}/${{ inputs.package-name }}/${{ env.version }} JFROG_ARTIFACTORY_URL: ${{ secrets.JFROG_ARTIFACTORY_URL }} JFROG_ARTIFACTORY_TOKEN: ${{ secrets.JFROG_ARTIFACTORY_TOKEN }} + - name: Report PyPI publish is handled by the caller + if: ${{ matrix.virtual-repo-name == 'pypi' || matrix.virtual-repo-name == 'test-pypi' }} + run: | + echo "::notice::Not publishing '${{ matrix.virtual-repo-name }}' here: PyPI trusted publishing must run as a direct step in the caller's top-level workflow, not through this reusable workflow. See the 'virtual-repo-names' input description." add_release_asset: name: Add release asset diff --git a/.github/workflows/reusable-python-release_pypi_assets.yml b/.github/workflows/reusable-python-release_pypi_assets.yml index 5e3da7a..2788b7e 100644 --- a/.github/workflows/reusable-python-release_pypi_assets.yml +++ b/.github/workflows/reusable-python-release_pypi_assets.yml @@ -9,8 +9,8 @@ on: type: string virtual-repo-names: description: > - List of repository names to publish to - (e.g. ["public-pypi-prod", "geophysics-pypi-prod"]) + List of repository names to publish to (e.g. ["public-pypi-prod", "geophysics-pypi-prod"]). + "pypi"/"test-pypi" are a deliberate no-op here; PyPI publishing runs in the caller (DEVOPS-1154). required: true type: string release-tag: @@ -69,3 +69,7 @@ jobs: artifactory-dir-path: ${{ matrix.virtual-repo-name }}/${{ inputs.package-name }}/${{ inputs.release-tag }} JFROG_ARTIFACTORY_URL: ${{ secrets.JFROG_ARTIFACTORY_URL }} JFROG_ARTIFACTORY_TOKEN: ${{ secrets.JFROG_ARTIFACTORY_TOKEN }} + - name: Report PyPI publish is handled by the caller + if: ${{ matrix.virtual-repo-name == 'pypi' || matrix.virtual-repo-name == 'test-pypi' }} + run: | + echo "::notice::Not publishing '${{ matrix.virtual-repo-name }}' here: PyPI trusted publishing must run as a direct step in the caller's top-level workflow, not through this reusable workflow. See the 'virtual-repo-names' input description." From 4c65b9dea11425403e65d340192eb35142c3bfd9 Mon Sep 17 00:00:00 2001 From: Romain Floreani Date: Wed, 26 Aug 2026 15:53:52 -0400 Subject: [PATCH 7/8] Making some fixes. --- .../action.yml | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .github/actions/reusable-python-download_dist_artifact/action.yml diff --git a/.github/actions/reusable-python-download_dist_artifact/action.yml b/.github/actions/reusable-python-download_dist_artifact/action.yml deleted file mode 100644 index 804bcaf..0000000 --- a/.github/actions/reusable-python-download_dist_artifact/action.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Download Python distribution files (workflow artifact) -description: > - Download built distribution files from a workflow artifact into a local - "dist-download" directory, ready to be published. -inputs: - artifact-name: - description: Name of the workflow artifact to download - required: true - type: string - -runs: - using: composite - steps: - - name: Download build artifact - uses: actions/download-artifact@v8 - with: - name: ${{ inputs.artifact-name }} - path: dist-download From 487c01c2f2f0b591f01b31157f6536fa23af9e91 Mon Sep 17 00:00:00 2001 From: Romain Floreani Date: Wed, 26 Aug 2026 15:54:35 -0400 Subject: [PATCH 8/8] Updating some fixes --- .../workflows/reusable-python-publish_pypi_package.yml | 9 ++++++--- .../workflows/reusable-python-release_pypi_assets.yml | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/reusable-python-publish_pypi_package.yml b/.github/workflows/reusable-python-publish_pypi_package.yml index 06c3b96..ecde433 100644 --- a/.github/workflows/reusable-python-publish_pypi_package.yml +++ b/.github/workflows/reusable-python-publish_pypi_package.yml @@ -24,7 +24,7 @@ on: virtual-repo-names: description: > List of virtual repository names to publish to (e.g. ["public-pypi-dev", "geophysics-pypi-dev"]). - "pypi"/"test-pypi" are a deliberate no-op here; PyPI publishing runs in the caller (DEVOPS-1154). + "pypi"/"test-pypi" are a deliberate no-op here; PyPI publishing runs in the caller. required: true type: string os: @@ -141,10 +141,13 @@ jobs: artifactory-dir-path: ${{ matrix.virtual-repo-name }}/${{ inputs.package-name }}/${{ env.version }} JFROG_ARTIFACTORY_URL: ${{ secrets.JFROG_ARTIFACTORY_URL }} JFROG_ARTIFACTORY_TOKEN: ${{ secrets.JFROG_ARTIFACTORY_TOKEN }} - - name: Report PyPI publish is handled by the caller + - name: Fail on PyPI/TestPyPI virtual-repo-name if: ${{ matrix.virtual-repo-name == 'pypi' || matrix.virtual-repo-name == 'test-pypi' }} + env: + VIRTUAL_REPO_NAME: ${{ matrix.virtual-repo-name }} run: | - echo "::notice::Not publishing '${{ matrix.virtual-repo-name }}' here: PyPI trusted publishing must run as a direct step in the caller's top-level workflow, not through this reusable workflow. See the 'virtual-repo-names' input description." + echo "::error::Not publishing '${VIRTUAL_REPO_NAME}' here: PyPI trusted publishing must run as a direct step in the caller's top-level workflow, not through this reusable workflow. See the 'virtual-repo-names' input description." + exit 1 add_release_asset: name: Add release asset diff --git a/.github/workflows/reusable-python-release_pypi_assets.yml b/.github/workflows/reusable-python-release_pypi_assets.yml index 2788b7e..4cd4e56 100644 --- a/.github/workflows/reusable-python-release_pypi_assets.yml +++ b/.github/workflows/reusable-python-release_pypi_assets.yml @@ -69,7 +69,10 @@ jobs: artifactory-dir-path: ${{ matrix.virtual-repo-name }}/${{ inputs.package-name }}/${{ inputs.release-tag }} JFROG_ARTIFACTORY_URL: ${{ secrets.JFROG_ARTIFACTORY_URL }} JFROG_ARTIFACTORY_TOKEN: ${{ secrets.JFROG_ARTIFACTORY_TOKEN }} - - name: Report PyPI publish is handled by the caller + - name: Fail on PyPI/TestPyPI virtual-repo-name if: ${{ matrix.virtual-repo-name == 'pypi' || matrix.virtual-repo-name == 'test-pypi' }} + env: + VIRTUAL_REPO_NAME: ${{ matrix.virtual-repo-name }} run: | - echo "::notice::Not publishing '${{ matrix.virtual-repo-name }}' here: PyPI trusted publishing must run as a direct step in the caller's top-level workflow, not through this reusable workflow. See the 'virtual-repo-names' input description." + echo "::error::Not publishing '${VIRTUAL_REPO_NAME}' here: PyPI trusted publishing must run as a direct step in the caller's top-level workflow, not through this reusable workflow. See the 'virtual-repo-names' input description." + exit 1