ワンクリックで
release-pypi
Release the podonos Python SDK to PyPI. Trigger: "release", "publish to pypi", "pypi release", "ship sdk"
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Release the podonos Python SDK to PyPI. Trigger: "release", "publish to pypi", "pypi release", "ship sdk"
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | release-pypi |
| version | 1.0.0 |
| description | Release the podonos Python SDK to PyPI. Trigger: "release", "publish to pypi", "pypi release", "ship sdk" |
| allowed-tools | ["Bash","Read","Edit","Write","Grep","Glob","AskUserQuestion"] |
This skill automates the full release process for the podonos Python SDK. It handles version bumping, testing, building, uploading to Test PyPI (always), user confirmation, uploading to Production PyPI, verification, git tagging, and GitHub Release creation.
Parse {{ARGUMENTS}} to determine the release type:
| Input | Behavior |
|---|---|
| (empty) | Release the current version as-is (no bump) |
patch | Bump patch: e.g., 0.35.0 -> 0.35.1 |
minor | Bump minor: e.g., 0.35.0 -> 0.36.0 |
major | Bump major: e.g., 0.35.0 -> 1.0.0 |
X.Y.Z | Bump to explicit version (must be > current) |
Validate the input:
patch, minor, major, or ^\d+\.\d+\.\d+$, STOP:
"Invalid argument: '{input}'. Usage: /release-pypi [patch|minor|major|X.Y.Z]"Store the result as TARGET_VERSION (one of: patch, minor, major, an explicit
version string, or empty for no bump).
Run ALL of these checks. Stop on any failure unless noted otherwise.
git status --porcelain
If output is non-empty, STOP: "Working tree is not clean. Commit or stash changes first."
git branch --show-current
If not main, warn the user and ask via AskUserQuestion:
git fetch origin main && git diff --quiet HEAD origin/main
If diverged, STOP: "Local branch is behind origin/main. Pull first."
test -f ~/.pypirc && echo "OK" || echo "MISSING"
If MISSING, STOP: "~/.pypirc not found. Create it with your PyPI and Test PyPI API tokens. See: https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#create-an-account"
.venv/bin/coverage run --source=./podonos -m pytest && .venv/bin/coverage report
NOTE: --source is a coverage flag, NOT a pytest flag. It must come before -m pytest.
If tests fail, STOP. No skip flag, no exceptions, not even for hotfixes.
Parse the coverage percentage from the output. If coverage < 70%, warn: "Coverage is {X}% (minimum: 70%)." Ask via AskUserQuestion:
NOTE: Always use .venv/bin/python — the system python may not exist or lack required modules.
.venv/bin/python -m build --version && .venv/bin/python -m twine --version && .venv/bin/coverage --version
If any is missing, install them: .venv/bin/python -m pip install build twine coverage
NOTE: The venv may lack pip. If so, bootstrap it first:
.venv/bin/python -m ensurepip --upgrade
.venv/bin/python -m pip index versions podonos
If CURRENT_VERSION (or intended RELEASE_VERSION) already exists on PyPI and no bump was requested, warn the user early: "v{VERSION} already exists on PyPI. You must bump the version." Ask for patch/minor/major bump before proceeding.
Ask via AskUserQuestion:
Do NOT use run_integration_tests.sh — it has multiple unresolved issues:
conda which may not be installed (brew install miniconda to install)conda activate doesn't work in non-interactive scripts without conda initset -e — silently swallows all errors and prints success regardless--api_key to integration_test_all.pyInstead, run the integration test directly. Pull the API key from 1Password:
API_KEY=$(op read "op://Engineering/DEV Podonos API Key/password")
.venv/bin/python tests/integration/integration_test_all.py --api_key="$API_KEY"
This must be run from the project root directory. If the op CLI is not installed or
not authenticated, ask the user for the API key manually.
If skipped, note "Integration tests: skipped" for the summary.
Extract versions using grep (never hardcode line numbers):
grep '^version' pyproject.toml | head -1 | sed 's/.*"\(.*\)".*/\1/'
grep '__version__' podonos/__init__.py | sed 's/.*"\(.*\)".*/\1/'
Verify both match. If they don't, STOP: "Version mismatch between pyproject.toml and init.py"
Store as CURRENT_VERSION.
Calculate RELEASE_VERSION from CURRENT_VERSION and TARGET_VERSION:
patch: increment the third number (0.35.0 -> 0.35.1)minor: increment the second number, reset third (0.35.0 -> 0.36.0)major: increment the first number, reset second and third (0.35.0 -> 1.0.0)X.Y.Z: validate format matches ^\d+\.\d+\.\d+$, verify > CURRENT_VERSIONUpdate both files using the Edit tool:
pyproject.toml: replace version = "{CURRENT_VERSION}" with version = "{RELEASE_VERSION}"podonos/__init__.py: replace __version__ = "{CURRENT_VERSION}" with __version__ = "{RELEASE_VERSION}"git log $(git describe --tags --abbrev=0 2>/dev/null || git rev-list --max-parents=0 HEAD)..HEAD --oneline
If the git log returns no commits, warn: "No commits found since last tag. Changelog will be empty." Ask via AskUserQuestion:
Rewrite the raw git log entries into clean, human-readable bullet points. Focus on user-facing changes, group related commits, and remove noise (merge commits, CI fixes, etc.).
Prepend to History.md at the top of the file:
## {RELEASE_VERSION}
- {changelog entry 1}
- {changelog entry 2}
...
Store the changelog entries as CHANGELOG_ENTRY for use in the GitHub Release later.
git add pyproject.toml podonos/__init__.py History.md
git commit -m "Release v{RELEASE_VERSION}"
Do NOT push. Push happens in Step 8, only after PyPI upload succeeds.
Store CURRENT_VERSION as RELEASE_VERSION. No files to modify.
Read the latest section from History.md (everything under the first ## X.Y.Z heading
until the next ## heading) and store as CHANGELOG_ENTRY.
Verify the package installs and imports correctly before building:
.venv/bin/python -m venv /tmp/podonos-pre-check && \
source /tmp/podonos-pre-check/bin/activate && \
pip install -e . && \
python -c "import podonos; print(podonos.__version__)" && \
deactivate
rm -rf /tmp/podonos-pre-check
NOTE: Use pip install -e . (not pip install -r requirements.txt) — the package should
install all its own dependencies automatically via pyproject.toml [project.dependencies].
If import fails or version doesn't match RELEASE_VERSION, STOP:
"Local install check failed. Fix the issue before proceeding."
rm -rf dist/ podonos.egg-info/
.venv/bin/python -m build
ls dist/
Verify that dist/ contains both a .tar.gz and a .whl file.
If either is missing, STOP: "Build failed — check output above."
.venv/bin/python -m twine upload --repository testpypi dist/*
Wait for propagation:
sleep 10
Verify installation from Test PyPI in a temp venv:
.venv/bin/python -m venv /tmp/podonos-release-test && \
source /tmp/podonos-release-test/bin/activate && \
pip install --no-cache-dir --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ podonos && \
python -c "import podonos; print(podonos.__version__)" && \
deactivate
rm -rf /tmp/podonos-release-test
NOTE: Use --index-url (not -i) for Test PyPI, plus --extra-index-url pointing to
production PyPI. This lets pip find the podonos package on Test PyPI while resolving its
dependencies (glog, soundfile, etc.) from production PyPI. Using -i alone will fail
because Test PyPI doesn't host all dependency packages.
If install fails due to missing dependencies on Test PyPI (common — Test PyPI doesn't have all packages), warn but do NOT block. Note: "Test PyPI install had dependency issues (expected — Test PyPI is incomplete). The package itself uploaded successfully."
If twine upload fails with "File already exists", warn: "This version already exists on Test PyPI. This often happens when re-running a release. Bump to a new version (e.g., /release-pypi patch) or delete the existing Test PyPI version at https://test.pypi.org/manage/project/podonos/"
If twine upload fails for other reasons (auth/network), STOP with guidance.
This step is non-negotiable. Always ask before uploading to production PyPI.
Use AskUserQuestion to present a release summary:
Ready to release podonos v{RELEASE_VERSION} to production PyPI.
- Unit tests: PASSED (coverage: {X}%)
- Integration tests: {PASSED|SKIPPED}
- Local install check: PASSED
- Build: OK ({list .tar.gz and .whl filenames})
- Test PyPI upload: OK
- Test PyPI install verification: {OK|DEPS_MISSING (expected)}
Options:
A) Yes, release v{RELEASE_VERSION} to production PyPI
B) No, abort (artifacts remain in dist/)
If user chooses B, STOP: "Release aborted. Built artifacts are still in dist/ if you want to inspect them. The version bump commit is local only (not pushed)."
If a version bump commit was made, offer to revert it:
git reset --soft HEAD~1).venv/bin/python -m twine upload dist/*
If this fails with an auth error, provide guidance: "Upload failed. Check that ~/.pypirc has a valid [pypi] section with your API token. Generate one at: https://pypi.org/manage/account/token/"
If this fails with "File already exists", warn: "This version already exists on PyPI. You cannot re-upload the same version. Bump to a new version and try again."
Wait for PyPI propagation (30 seconds — 15 is often not enough):
sleep 30
Verify installation from production PyPI in a temp venv:
.venv/bin/python -m venv /tmp/podonos-release-verify && \
source /tmp/podonos-release-verify/bin/activate && \
pip install --no-cache-dir podonos=={RELEASE_VERSION} && \
python -c "import podonos; print(podonos.__version__)" && \
deactivate
rm -rf /tmp/podonos-release-verify
NOTE: Pin the version with podonos=={RELEASE_VERSION} to ensure you're testing the
new release, not a cached older version.
IMPORTANT: Do NOT pre-install dependencies (e.g., pip install -r requirements.txt)
before installing from PyPI. The whole point of this check is to verify that
pip install podonos automatically resolves all dependencies declared in
pyproject.toml [project.dependencies]. If dependencies are missing from pyproject.toml,
this step should catch it.
Verify the installed version matches RELEASE_VERSION.
If it doesn't match, warn: "Installed version {X} doesn't match expected {RELEASE_VERSION}.
PyPI may still be propagating. Check manually: pip install podonos=={RELEASE_VERSION}"
Only run this step after Step 7 succeeds.
git tag -a "v{RELEASE_VERSION}" -m "Release v{RELEASE_VERSION}"
Branch protection: The main branch has branch protection rules that prevent direct
pushes. Instead of git push origin main, create a release branch and PR:
git checkout -b release/v{RELEASE_VERSION}
git push origin release/v{RELEASE_VERSION} --follow-tags
Then create a PR:
gh pr create --title "Release v{RELEASE_VERSION}" \
--body "Release v{RELEASE_VERSION} to PyPI" \
--base main --head release/v{RELEASE_VERSION}
If direct push to main works (no branch protection), that's fine too. But be prepared for it to fail and fall back to the PR approach.
Do NOT force push.
After the PR is merged, switch back to main and clean up:
git checkout main && git pull origin main && git branch -d release/v{RELEASE_VERSION}
gh release create "v{RELEASE_VERSION}" \
--title "v{RELEASE_VERSION}" \
--notes "{CHANGELOG_ENTRY}"
GitHub automatically marks this as the "Latest" release. The BE can query
https://api.github.com/repos/podonos/podonos-pysdk/releases/latest to get the
current SDK version programmatically.
If gh CLI is not available or not authenticated, warn but don't fail:
"GitHub Release not created (gh CLI unavailable). Create manually at:
https://github.com/podonos/podonos-pysdk/releases/new?tag=v{RELEASE_VERSION}"
Print the final release summary:
=== Release Complete: podonos v{RELEASE_VERSION} ===
PyPI: https://pypi.org/project/podonos/{RELEASE_VERSION}/
Test PyPI: https://test.pypi.org/project/podonos/{RELEASE_VERSION}/
GitHub Release: https://github.com/podonos/podonos-pysdk/releases/tag/v{RELEASE_VERSION}
Git Tag: v{RELEASE_VERSION}
Install: pip install podonos=={RELEASE_VERSION}
Unit tests: PASSED (coverage: {X}%)
Integration tests: {PASSED|SKIPPED}
Post-release checklist:
- [ ] Update @Get("version/sdk") in the BE API with the new version
{If major version bump:}
- [ ] **BREAKING CHANGE** — updating @Get("version/sdk") in the BE API is likely required
- [ ] Notify users of breaking changes