Skip to content

1.4.1

1.4.1 #25

Workflow file for this run

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