1.4.1 #25
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 | |
| on: | |
| push: | |
| branches: [main] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| jobs: | |
| release: | |
| name: Release | |
| # Must be Linux: python-semantic-release is a Docker container action, which | |
| # only runs on Linux runners. Wheel build + PyPI publish are platform-agnostic; | |
| # the macOS-only `brew install` check lives in homebrew-test.yml. | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| id-token: write | |
| env: | |
| # Surfaced at job level so steps can gate on its presence in `if:`. | |
| HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| WELCHOST_POSTHOG_KEY: ${{ secrets.WELCHOST_POSTHOG_KEY }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| # Push the version-bump commit over SSH via the release deploy key, which | |
| # is a bypass actor on the protected `main` branch ruleset. The action | |
| # still uses GITHUB_TOKEN below for the GitHub Release API. | |
| ssh-key: ${{ secrets.RELEASE_SSH_KEY }} | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.13" | |
| - name: Install dependencies | |
| run: pip install -e ".[dev]" | |
| - name: Lint | |
| run: ruff check src/ tests/ | |
| - name: Test | |
| run: pytest --tb=short -q | |
| - name: Bake telemetry key into the build | |
| # The PostHog project key is never committed to this public repo. We write | |
| # it into a gitignored _secrets.py here, before semantic-release builds the | |
| # sdist/wheel, so the published artifact carries the key while the source | |
| # tree does not. Skipped when the secret is unset → that release ships with | |
| # telemetry off rather than failing. | |
| if: env.WELCHOST_POSTHOG_KEY != '' | |
| run: | | |
| printf '%s\n%s\n' \ | |
| '# Generated by CI at release time from the WELCHOST_POSTHOG_KEY secret.' \ | |
| "POSTHOG_API_KEY = \"${WELCHOST_POSTHOG_KEY}\"" \ | |
| > src/welchost/_secrets.py | |
| - name: Python Semantic Release | |
| id: release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Run semantic-release as a CLI (installed via .[dev]) rather than the | |
| # Docker container action. The action pushes over HTTPS as | |
| # github-actions[bot], which the protected-main ruleset rejects. The | |
| # CLI pushes over the SSH remote configured by checkout (ssh-key), | |
| # authenticating as the release deploy key — a bypass actor on the | |
| # ruleset. GH_TOKEN is still used for the GitHub Release API. | |
| git config user.name "Welchost Contributors" | |
| git config user.email "noreply@welchost.dev" | |
| echo "Push remote (must be SSH for the deploy-key bypass):" | |
| git remote -v | |
| prev="$(git describe --tags --abbrev=0 2>/dev/null || echo none)" | |
| semantic-release -v version | |
| curr="$(git describe --tags --abbrev=0 2>/dev/null || echo none)" | |
| if [ "$curr" != "$prev" ]; then | |
| echo "released=true" >> "$GITHUB_OUTPUT" | |
| echo "version=${curr#v}" >> "$GITHUB_OUTPUT" | |
| semantic-release -v publish | |
| else | |
| echo "released=false" >> "$GITHUB_OUTPUT" | |
| echo "No release: no version-bumping commits since $prev." | |
| fi | |
| - name: Publish to PyPI | |
| if: steps.release.outputs.released == 'true' | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| password: ${{ secrets.PYPI_TOKEN }} | |
| - name: Update Homebrew tap | |
| # Bump the tap formula directly. We don't use bump-homebrew-formula-action: | |
| # it defaults to a fork+PR flow and fails with "invalid ref: refs/heads/main" | |
| # because the token owner (scoobynko) also owns the tap, so the fork it wants | |
| # can't exist. Instead, compute the sha256 from the freshly built sdist, swap | |
| # the one main url/sha pair (resource blocks are untouched — only the main | |
| # package filename matches "welchost-<ver>.tar.gz"), and push. The token is an | |
| # admin, so it bypasses the tap's protect-main ruleset. | |
| # Skips until the tap token is configured, so a PyPI-only release stays green. | |
| if: steps.release.outputs.released == 'true' && env.HOMEBREW_TAP_TOKEN != '' | |
| env: | |
| VERSION: ${{ steps.release.outputs.version }} | |
| TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| SHA=$(sha256sum "dist/welchost-${VERSION}.tar.gz" | awk '{print $1}') | |
| # Canonical hashed sdist URL from PyPI (retry: the index lags the upload). | |
| URL="" | |
| for i in 1 2 3 4 5 6; do | |
| URL=$(curl -fsSL "https://pypi.org/pypi/welchost/${VERSION}/json" \ | |
| | python -c "import sys,json;print([u for u in json.load(sys.stdin)['urls'] if u['packagetype']=='sdist'][0]['url'])" 2>/dev/null) \ | |
| && [ -n "$URL" ] && break | |
| echo "PyPI not ready (attempt $i); retrying in 5s"; sleep 5 | |
| done | |
| [ -n "$URL" ] || { echo "::error::could not resolve sdist URL for ${VERSION}"; exit 1; } | |
| echo "Bumping formula to ${VERSION}: ${URL} (${SHA})" | |
| git clone --depth 1 "https://x-access-token:${TAP_TOKEN}@github.com/scoobynko/homebrew-welchost.git" tap | |
| python - "$URL" "$SHA" <<'PY' | |
| import re, sys | |
| url, sha = sys.argv[1], sys.argv[2] | |
| path = "tap/Formula/welchost.rb" | |
| text = open(path).read() | |
| text, n = re.subn( | |
| r'url "[^"]*welchost-[^"]*\.tar\.gz"\n(\s*)sha256 "[0-9a-f]+"', | |
| f'url "{url}"\n\\1sha256 "{sha}"', text, count=1) | |
| assert n == 1, f"expected exactly 1 main-package substitution, got {n}" | |
| open(path, "w").write(text) | |
| PY | |
| cd tap | |
| git config user.name "welchost-release" | |
| git config user.email "release@welchost.dev" | |
| git commit -am "chore: bump welchost to ${VERSION}" | |
| git push origin HEAD:main |