Skip to content

ci: add Python SDK publish workflow with version validation#700

Open
wbzdssm wants to merge 1 commit into
TencentCloud:masterfrom
wbzdssm:feat/python-sdk-publish-workflow
Open

ci: add Python SDK publish workflow with version validation#700
wbzdssm wants to merge 1 commit into
TencentCloud:masterfrom
wbzdssm:feat/python-sdk-publish-workflow

Conversation

@wbzdssm

@wbzdssm wbzdssm commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Add .github/workflows/publish-python-sdk.yml to automate publishing the Python SDK to PyPI.

Changes from PR #638

  • Trigger: v*python-sdk-v* (dedicated Python SDK version tag, decoupled from repo-level tags)
  • Version validation: tag version must match pyproject.toml version AND cubesandbox/__init__.py __version__ — fails fast if mismatched
  • Change detection: compares against previous python-sdk-v* tag (not v*), only publishes when sdk/python/ has actual changes

Workflow steps

  1. Triggered on python-sdk-v* tag push
  2. Strong version check: extract version from tag, compare with pyproject.toml and __init__.py — exit 1 on mismatch
  3. Change detection: diff sdk/python/ since last python-sdk-v* tag — skip if no changes
  4. Run tests (pytest)
  5. Build package (python -m build)
  6. Validate (twine check)
  7. Publish to PyPI

Required secrets

  • CUBE_PYPI_TOKEN — PyPI upload token

Tag convention

Use tags like python-sdk-v0.3.0 where 0.3.0 matches the version in pyproject.toml.

Closes #638

- Trigger on python-sdk-v* tags (dedicated Python SDK version tag)
- Strong version check: tag version must match pyproject.toml and __init__.py
- Detect sdk/python/ changes since previous python-sdk-v* tag
- Run tests, build, twine check, then publish to PyPI
- Skip publish if no sdk/python/ changes detected
echo "Tag version: $TAG_VERSION"

# Extract version from pyproject.toml
PYPROJECT_VERSION=$(grep -m1 '^version' pyproject.toml | sed 's/version *= *"\(.*\)"/\1/')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fragile version extraction: The pattern ^version matches any line starting with version (e.g., version_format, or a value under [tool.*] sections). Consider using Python's tomllib (available in Python 3.11) for structured TOML parsing:

PYPROJECT_VERSION=$(python3 -c "import tomllib; f=open('pyproject.toml','rb'); print(tomllib.load(f)['project']['version'])")
echo "pyproject.toml version: $PYPROJECT_VERSION"

# Extract version from __init__.py
INIT_VERSION=$(grep -m1 '__version__' cubesandbox/__init__.py | sed 's/.*__version__ *= *"\(.*\)".*/\1/')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fragile version extraction: grep -m1 '__version__' matches comment lines containing __version__ (e.g., # Check __version__ before release). Anchor with ^ to only match actual assignments:

INIT_VERSION=$(grep -m1 '^__version__' cubesandbox/__init__.py | sed 's/^__version__ *= *"\(.*\)".*/\1/')
if: steps.check_changes.outputs.changed == 'true'
working-directory: sdk/python
run: |
pip install -e ".[dev]" 2>/dev/null || pip install -e .

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error silencing: 2>/dev/null discards ALL stderr from the first pip install, including real failure messages. If .[dev] install fails and the fallback pip install -e . succeeds (installing without test dependencies), subsequent python -m pytest will fail with a confusing ModuleNotFoundError (or worse — silently pass without coverage). Remove the 2>/dev/null so real errors surface immediately.


- name: Publish to PyPI
if: steps.check_changes.outputs.changed == 'true'
uses: pypa/gh-action-pypi-publish@release/v1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutable reference: release/v1 is a floating branch whose commit can change without notice. For a step handling authentication credentials, pin to an immutable commit SHA. Dependabot can manage updates.

uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: sdk/python/dist/
password: ${{ secrets.CUBE_PYPI_TOKEN }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider OIDC trusted publishing: Using a long-lived PyPI token creates a permanent credential that, if leaked, allows anyone to publish malicious packages under the project name. PyPI's OIDC trusted publishing eliminates this risk — pypa/gh-action-pypi-publish supports it natively when no password is provided. Add id-token: write to the job's permissions block and remove this line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant