Release 0.4.102 for direct #113
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish to PyPI | |
| run-name: Release ${{ inputs.release_tag || github.ref_name }} for ${{ inputs.release_plan || 'direct' }} | |
| on: | |
| push: | |
| tags: | |
| - '[0-9]+.[0-9]+.[0-9]+*' | |
| workflow_dispatch: | |
| inputs: | |
| release_tag: | |
| description: 'Existing immutable SDK release tag; empty permits a build-only run' | |
| required: false | |
| type: string | |
| default: '' | |
| release_plan: | |
| description: 'Immutable release-plan tag initiating this recovery run' | |
| required: false | |
| type: string | |
| default: 'direct' | |
| publish: | |
| description: 'Publish the exact release tag to PyPI' | |
| required: false | |
| type: boolean | |
| default: false | |
| dry_run: | |
| description: 'Legacy TestPyPI dry-run guard' | |
| required: false | |
| type: boolean | |
| default: true | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: release-${{ inputs.release_tag || github.ref_name }} | |
| cancel-in-progress: false | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| release_tag: ${{ steps.release_source.outputs.tag }} | |
| release_commit: ${{ steps.release_source.outputs.commit }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| ref: >- | |
| ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag != '' | |
| && format('refs/tags/{0}', inputs.release_tag) || github.ref }} | |
| - name: Resolve exact release identity | |
| id: release_source | |
| env: | |
| REQUESTED_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref_name }} | |
| PUBLISH_REQUESTED: ${{ github.event_name == 'push' || inputs.publish }} | |
| run: | | |
| set -euo pipefail | |
| package_version="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')" | |
| head_commit="$(git rev-parse HEAD)" | |
| if [ "$PUBLISH_REQUESTED" = true ]; then | |
| if [[ ! "$REQUESTED_TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-+][0-9A-Za-z.-]+)?$ ]]; then | |
| printf 'release tag must be an exact SDK SemVer: %s\n' "$REQUESTED_TAG" >&2 | |
| exit 1 | |
| fi | |
| if [ "$REQUESTED_TAG" != "$package_version" ]; then | |
| printf 'release tag %s does not match package version %s\n' "$REQUESTED_TAG" "$package_version" >&2 | |
| exit 1 | |
| fi | |
| tag_commit="$(git rev-list -n 1 "$REQUESTED_TAG")" | |
| if [ "$tag_commit" != "$head_commit" ]; then | |
| printf 'release tag %s points to %s, not checkout commit %s\n' \ | |
| "$REQUESTED_TAG" "$tag_commit" "$head_commit" >&2 | |
| exit 1 | |
| fi | |
| else | |
| REQUESTED_TAG="$package_version" | |
| fi | |
| { | |
| printf 'tag=%s\n' "$REQUESTED_TAG" | |
| printf 'commit=%s\n' "$head_commit" | |
| } >> "$GITHUB_OUTPUT" | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Install build tools | |
| run: pip install build twine | |
| - name: Build package | |
| run: python -m build | |
| - name: Check package | |
| run: twine check dist/* | |
| - name: Smoke test built package | |
| run: python scripts/smoke-built-package.py | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: dist | |
| path: dist/ | |
| publish: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| if: >- | |
| (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) || | |
| (github.event_name == 'workflow_dispatch' && inputs.publish) | |
| environment: pypi | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: dist | |
| path: dist/ | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| password: ${{ secrets.PYPI_TOKEN }} | |
| print-hash: true | |
| skip-existing: true | |
| - name: Create the source GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_TAG: ${{ needs.build.outputs.release_tag }} | |
| run: | | |
| if ! gh release view "$RELEASE_TAG" >/dev/null 2>&1; then | |
| arguments=(--verify-tag --generate-notes --title "$RELEASE_TAG") | |
| if [[ "$RELEASE_TAG" == *-* ]]; then | |
| arguments+=(--prerelease) | |
| fi | |
| gh release create "$RELEASE_TAG" "${arguments[@]}" | |
| fi | |
| verify-docs-release-audit: | |
| needs: [build, publish] | |
| runs-on: ubuntu-latest | |
| if: >- | |
| (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) || | |
| (github.event_name == 'workflow_dispatch' && inputs.publish) | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ needs.build.outputs.release_tag }} | |
| - name: Verify live docs release audit after PyPI publish | |
| env: | |
| DOCS_RELEASE_AUDIT_ARTIFACT: sdk-python | |
| DOCS_RELEASE_AUDIT_VERSION: ${{ needs.build.outputs.release_tag }} | |
| DOCS_RELEASE_AUDIT_EVIDENCE: docs-release-audit-evidence.json | |
| DOCS_RELEASE_AUDIT_HANDOFF: docs-release-audit-handoff.json | |
| DOCS_RELEASE_AUDIT_ENFORCEMENT: advisory | |
| run: scripts/ci/check-docs-release-audit.sh | |
| - name: Upload docs release audit evidence | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: docs-release-audit-evidence | |
| path: | | |
| docs-release-audit-evidence.json | |
| docs-release-audit-handoff.json | |
| if-no-files-found: warn | |
| publish-test: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'workflow_dispatch' && !inputs.dry_run && !inputs.publish | |
| environment: test-pypi | |
| steps: | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: dist | |
| path: dist/ | |
| - name: Publish to TestPyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| password: ${{ secrets.TEST_PYPI_TOKEN }} | |
| repository-url: https://test.pypi.org/legacy/ | |
| print-hash: true |