name: Publish Python 🐍 distribution 📦 to PyPI # This workflow creates immutable releases: # 1. Build packages # 2. Publish to PyPI (only on tag push) # 3. After successful PyPI publish: # - Sign artifacts # - Check if GitHub release exists (idempotent) # - Create release with all artifacts atomically # This ensures releases cannot be modified once published. on: push: tags: - 'v*' workflow_dispatch: inputs: version: description: 'Version to release (e.g., 0.6.8)' required: true type: string permissions: contents: read id-token: write jobs: build: name: Build distribution 📦 runs-on: ubuntu-latest permissions: contents: read id-token: write steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: persist-credentials: false - name: Set up Python uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version: "3.13" - name: Install pypa/build run: python3 -m pip install build --user - name: Build a binary wheel and a source tarball run: python3 -m build - name: Store the distribution packages uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: python-package-distributions path: dist/ publish-to-pypi: name: Publish Python 🐍 distribution 📦 to PyPI if: startsWith(github.ref, 'refs/tags/') needs: - build runs-on: ubuntu-latest environment: name: pypi url: https://pypi.org/p/rns-page-node permissions: id-token: write contents: read steps: - name: Download all the dists uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: python-package-distributions path: dist/ - name: Publish distribution 📦 to PyPI uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e github-release: name: Sign the Python 🐍 distribution 📦 and create GitHub Release needs: - publish-to-pypi runs-on: ubuntu-latest permissions: contents: write id-token: write steps: - name: Download all the dists uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: python-package-distributions path: dist/ - name: Sign the dists with Sigstore uses: sigstore/gh-action-sigstore-python@f7ad0af51a5648d09a20d00370f0a91c3bdf8f84 # v3.0.1 with: inputs: >- ./dist/*.tar.gz ./dist/*.whl - name: Check if release exists id: check_release env: GITHUB_TOKEN: ${{ github.token }} run: | if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then echo "exists=true" >> $GITHUB_OUTPUT echo "Release $GITHUB_REF_NAME already exists, skipping creation" else echo "exists=false" >> $GITHUB_OUTPUT echo "Release $GITHUB_REF_NAME does not exist, will create" fi continue-on-error: true - name: Create GitHub Release with artifacts if: steps.check_release.outputs.exists != 'true' env: GITHUB_TOKEN: ${{ github.token }} run: >- gh release create "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --title "Release $GITHUB_REF_NAME" --notes "PyPI: https://pypi.org/project/rns-page-node/$GITHUB_REF_NAME/" dist/*