Merge pull request #12 from pip-install-python/admin-nav-owner-only #1
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: Release | |
| # Tag-driven publish. Push a v* tag and this builds, verifies, publishes to | |
| # PyPI via OIDC trusted publishing, and opens a GitHub Release. | |
| # | |
| # NO API TOKEN IS STORED ANYWHERE. Trusted publishing has PyPI verify a | |
| # short-lived OIDC token minted by GitHub for this specific repo + workflow + | |
| # environment, so there is no long-lived secret to leak or rotate. One-time | |
| # setup on PyPI (see RELEASING.md): | |
| # pypi.org -> your project -> Publishing -> Add a new pending publisher | |
| # Owner: pip-install-python | |
| # Repository: dash-leaflet2 | |
| # Workflow name: release.yml | |
| # Environment name: pypi | |
| on: | |
| push: | |
| tags: ["v*"] | |
| workflow_dispatch: | |
| inputs: | |
| dry_run: | |
| description: "Build and verify, but publish to TestPyPI instead of PyPI" | |
| type: boolean | |
| default: true | |
| # Read-only by default; the two jobs that need more ask for it themselves | |
| # (`id-token: write` to publish, `contents: write` to cut the GitHub Release). | |
| permissions: | |
| contents: read | |
| # Never let two releases race. NOT cancel-in-progress: a half-cancelled | |
| # publish is the one state worth avoiding here, because a version can be | |
| # uploaded to PyPI exactly once and is not replaceable afterwards. | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| verify: | |
| name: Verify the tag | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Tag must match the version in pyproject.toml | |
| # Catches the classic release mistake: bumping the code but tagging the | |
| # old number (or the reverse). PyPI would happily accept the mismatch. | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| run: | | |
| TAG="${GITHUB_REF_NAME#v}" | |
| PY_VER=$(python -c "import re;print(re.search(r'^version = \"([^\"]+)\"', open('pyproject.toml').read(), re.M).group(1))") | |
| echo "tag=$TAG pyproject=$PY_VER" | |
| if [ "$TAG" != "$PY_VER" ]; then | |
| echo "::error::Tag v$TAG does not match pyproject version $PY_VER" | |
| exit 1 | |
| fi | |
| - name: Release consistency check | |
| run: python scripts/check_release.py | |
| build: | |
| name: Build distributions | |
| needs: verify | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| - name: Smoke test against the current Dash | |
| run: | | |
| python -m pip install --upgrade pip | |
| grep -v 'COMPAT-MATRIX: dash' requirements.txt > /tmp/reqs.txt | |
| python -m pip install "dash[fastapi]" -r /tmp/reqs.txt | |
| # markdown2dash is NOT in requirements.txt: it declares gunicorn<22 | |
| # against the CVE-driven gunicorn>=23 floor, so it installs without | |
| # its dependency graph. pages/markdown.py imports it, so the smoke | |
| # test below cannot even reach a page without this line. Same pair as | |
| # the Dockerfile and ci.yml. | |
| python -m pip install --no-deps markdown2dash==0.1.2 | |
| python scripts/smoke_test.py | |
| - name: Build | |
| run: | | |
| python -m pip install build twine | |
| python -m build | |
| python -m twine check dist/* | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: dist | |
| path: dist/ | |
| publish: | |
| name: Publish to PyPI | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| # The environment name must match the pending publisher configured on PyPI. | |
| # Add a required reviewer on this environment in repo settings if you want | |
| # a human approval gate between the tag and the upload. | |
| environment: | |
| name: pypi | |
| url: https://pypi.org/p/dash-leaflet2 | |
| permissions: | |
| # `id-token: write` is what lets GitHub mint the OIDC token PyPI checks. | |
| # Without it trusted publishing fails with an opaque 403. | |
| id-token: write | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: dist | |
| path: dist/ | |
| - name: Publish to TestPyPI (manual dry run) | |
| if: github.event_name == 'workflow_dispatch' && inputs.dry_run | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| repository-url: https://test.pypi.org/legacy/ | |
| - name: Publish to PyPI | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| github-release: | |
| name: GitHub Release | |
| needs: publish | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: dist | |
| path: dist/ | |
| - name: Extract this version's CHANGELOG section | |
| run: | | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| awk -v v="$VERSION" ' | |
| $0 ~ "^## \\[" v "\\]" {found=1; next} | |
| found && /^## \[/ {exit} | |
| found {print} | |
| ' CHANGELOG.md > release-notes.md | |
| if [ ! -s release-notes.md ]; then | |
| echo "See CHANGELOG.md for details." > release-notes.md | |
| fi | |
| cat release-notes.md | |
| - uses: softprops/action-gh-release@v2 | |
| with: | |
| body_path: release-notes.md | |
| files: dist/* | |
| generate_release_notes: true |