From ff7213f7a61267a17fce6ef9658df20e92573c04 Mon Sep 17 00:00:00 2001 From: Alibek Tokayev Date: Fri, 11 Sep 2026 15:31:55 -0600 Subject: [PATCH 1/2] CCL-467: fix CI coverage target and make publishing tag-driven CI has never measured anything: python.yml ran `pytest --cov={{packageName}}`, an unrendered Mustache template, so coverage reported "No data to report" while the job still exited 0. Point it at the real package. Publishing was driven by `release: published`, which decouples the artifact from the release name: run 29043124220 fired from the release tagged v4.21.1 but ran against ref v4.20.0 and published 4.20.0, so 4.21.1 never reached PyPI. Trigger on tag push instead, and fail the job when the tag does not match the version of the distribution actually built. Also bump the deprecated checkout@v3/setup-python@v3 actions and drop .travis.yml, which has never reported a commit status on this repository. --- .github/workflows/publish.yml | 85 ++++++++++++++++++++++++++--------- .github/workflows/python.yml | 20 +++++++-- .travis.yml | 17 ------- 3 files changed, 81 insertions(+), 41 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b734509..f97bd35 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,35 +1,80 @@ +# NOTE: This file is HAND-MAINTAINED in this repository and has no upstream +# counterpart in CentML/platform. Keep the file name `publish.yml`: PyPI trusted +# publishing (OIDC) is bound to the workflow file name, so renaming it breaks +# publishing. See CCL-467. + name: publish +# Trigger on tag push rather than on `release: published`, so the tag itself is +# what selects the code being published. +# +# Under the old trigger the published artifact came from whatever tag the GitHub +# Release happened to target, which is decoupled from the release's name and can +# be edited afterwards. That is how 4.21.1 was lost: run 29043124220 fired from +# the release now titled "v4.21.11"/tagged v4.21.1, but ran against ref v4.20.0 +# and published 4.20.0. Seven tags never reached PyPI in total. +# +# Both tag spellings are matched on purpose: 4 of the 31 existing tags (3.2.5 - +# 3.2.8) carry no `v` prefix, and a tag that matches no pattern here would fail +# silently, which is the exact failure mode this workflow exists to remove. on: - release: - types: [published] + push: + tags: + - "v*" + - "[0-9]*" jobs: publish: runs-on: ubuntu-latest + # Scopes the OIDC token and allows a manual approval gate to be configured + # via required reviewers in the repository's environment settings. + environment: + name: pypi + url: https://pypi.org/project/platform-api-python-client/ permissions: id-token: write + contents: read steps: - - uses: actions/checkout@v3 - - name: setup-python - uses: actions/setup-python@v3 + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 with: python-version: "3.11" - architecture: "x64" - - name: install pypa/build - run: >- - python -m - pip install - build - --user - - name: build sdist(tarball) and bdist(wheel) to dist/ - run: >- # = python -m build . works the same way by default - python -m - build - --sdist - --wheel - --outdir dist/ - - name: publish to PyPI + + - name: Install build tooling + run: | + python -m pip install --upgrade pip + python -m pip install build twine + + - name: Build sdist and wheel + run: python -m build --sdist --wheel --outdir dist/ + + - name: Verify tag matches package version + # Read the version from the built distribution rather than from + # pyproject.toml. The project currently declares its version under + # [tool.poetry] while building with the setuptools backend (which reads + # setup.py), and CCL-470 will move it to a PEP 621 [project] table. The + # built artifact is the single source of truth in all of those layouts. + run: | + set -euo pipefail + TAG="${GITHUB_REF_NAME#v}" + VERSION="$(python -c ' + import pathlib + sdists = sorted(pathlib.Path("dist").glob("*.tar.gz")) + if len(sdists) != 1: + raise SystemExit(f"expected exactly one sdist, found {[p.name for p in sdists]}") + print(sdists[0].name.removesuffix(".tar.gz").rsplit("-", 1)[1]) + ')" + echo "tag=$TAG built version=$VERSION" + if [ "$TAG" != "$VERSION" ]; then + echo "::error::tag $TAG does not match built package version $VERSION" + exit 1 + fi + + - name: Check distribution metadata + run: python -m twine check --strict dist/* + + - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: repository-url: https://upload.pypi.org/legacy/ diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 91d5249..0f42c51 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -1,5 +1,17 @@ -# NOTE: This file is auto generated by OpenAPI Generator. -# URL: https://openapi-generator.tech +# NOTE: This file is HAND-MAINTAINED in this repository. Do not treat it as +# generated output, even though it originated from OpenAPI Generator. +# +# It intentionally diverges from the upstream copy at +# CentML/platform:client/python/platform_api_python_client/.github/workflows/python.yml, +# which still contains the unrendered `--cov={{packageName}}` template and a +# Python 3.8 matrix entry. +# +# It survives `sync_client.yml` today only because that workflow's `rm -rf *` +# and `cp -r .../*` globs skip dot-paths. CCL-468 proposes switching the copy to +# `cp -r .../.`, which DOES copy dotfiles and would silently revert this file. +# Before that lands, the upstream copies of `.github/workflows/python.yml` and +# `.travis.yml` must be deleted from the platform repo and added to its +# `.openapi-generator-ignore` (see CCL-467, CCL-468, CCL-470). # # ref: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python @@ -18,7 +30,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -28,4 +40,4 @@ jobs: pip install -r test-requirements.txt - name: Test with pytest run: | - pytest --cov={{packageName}} + pytest --cov=platform_api_python_client diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3ab8a2a..0000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -# ref: https://docs.travis-ci.com/user/languages/python -language: python -python: - - "3.8" - - "3.9" - - "3.10" - - "3.11" - - "3.12" - # uncomment the following if needed - #- "3.12-dev" # 3.12 development branch - #- "nightly" # nightly build -# command to install dependencies -install: - - "pip install -r requirements.txt" - - "pip install -r test-requirements.txt" -# command to run tests -script: pytest --cov=platform_api_python_client From 3081f27136c873168f4f795edd622fdb2cb810db Mon Sep 17 00:00:00 2001 From: atokayev Date: Fri, 11 Sep 2026 22:54:02 -0600 Subject: [PATCH 2/2] CCL-467: install the package in CI so packaging tests are not skipped The hand-written packaging tests arriving with the platform-side sync read the built distribution's metadata through importlib.metadata and skip when no distribution is installed, which is exactly the regression they guard against (every release up to 4.28.0 published requires_python: None). Installing the package also makes --cov measure the installed artifact. --- .github/workflows/python.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 0f42c51..65880eb 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -38,6 +38,9 @@ jobs: python -m pip install --upgrade pip pip install -r requirements.txt pip install -r test-requirements.txt + # install the package itself: the packaging tests read the built distribution's metadata + # through importlib.metadata and skip silently when it is absent + pip install . - name: Test with pytest run: | pytest --cov=platform_api_python_client