diff --git a/RELEASING.md b/RELEASING.md index 0b50ff4..41dc1e2 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -5,6 +5,7 @@ Every release uses `./scripts/release.sh`. Do not bump versions, tag, or create ## One-time setup - Install [GitHub CLI](https://cli.github.com/) (`gh`) and authenticate. +- Install [uv](https://docs.astral.sh/uv/). `prepare` relocks `uv.lock` with it, since the lock file records this project's own version and CI installs with `uv sync --locked`. - Ensure PyPI [trusted publishing](https://docs.pypi.org/trusted-publishers/) is configured for this repo (`publish.yml` uses the `pypi` GitHub environment). ## Release steps diff --git a/scripts/publish-workflow.sh b/scripts/publish-workflow.sh new file mode 100755 index 0000000..713f872 --- /dev/null +++ b/scripts/publish-workflow.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# Generate publish.yml for a package. Usage: publish-workflow.sh hotdata-framework +set -euo pipefail +pkg="${1:?package name}" +cat <&2 + exit 1 + fi + tag="\${GITHUB_REF_NAME#v}" + pkg_version=\$(python -c "import tomllib,pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])") + if [ "\$tag" != "\$pkg_version" ]; then + echo "Release tag (\$tag) does not match pyproject.toml version (\$pkg_version)" >&2 + exit 1 + fi + + - name: Build sdist and wheel + run: python -m build + + - name: Check distribution metadata + run: python -m twine check --strict dist/* + + - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + with: + name: dist + path: dist/ + + publish: + name: Publish to PyPI + needs: build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/${pkg} + permissions: + id-token: write + steps: + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + with: + name: dist + path: dist/ + + - name: Publish via Trusted Publishing + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 +EOF diff --git a/scripts/release.sh b/scripts/release.sh index 03aaeae..a9759e4 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -82,9 +82,18 @@ PY default_branch() { local remote="${1:-origin}" - git symbolic-ref --quiet "refs/remotes/${remote}/HEAD" 2>/dev/null | sed "s|refs/remotes/${remote}/||" \ - || { git branch -r | sed -n "s|^ ${remote}/\\(main\\|master\\)$|\\1|p" | head -1; } \ - || echo main + local branch + branch="$(git symbolic-ref --quiet "refs/remotes/${remote}/HEAD" 2>/dev/null | sed "s|refs/remotes/${remote}/||")" + if [[ -n "$branch" ]]; then + echo "$branch" + return + fi + branch="$(git branch -r --list "${remote}/main" "${remote}/master" | sed "s|^[[:space:]]*${remote}/||" | head -1)" + if [[ -n "$branch" ]]; then + echo "$branch" + return + fi + echo main } ensure_clean() { @@ -103,6 +112,7 @@ cmd_prepare() { [[ -n "$bump" ]] || { usage; die "missing bump kind or explicit version"; } need gh need python3 + need uv ensure_clean local current new base branch pkg @@ -122,10 +132,12 @@ cmd_prepare() { set_version "$new" update_changelog "$new" + # uv.lock records this project's own version, and CI installs with --locked. + uv lock branch="release/v${new}" git checkout -b "$branch" - git add pyproject.toml CHANGELOG.md + git add pyproject.toml CHANGELOG.md uv.lock git commit -m "chore: release v${new}" pkg="$(get_pkg_name)"