Skip to content

Commit 0c67e1b

Browse files
committed
Add PyPI publish CD (release-labelled PR -> build & upload)
Adds two GitHub Actions workflows: - prepare-release.yml: manual dispatch; bumps version= in setup.py and RequestExecutor.CLIENT_VERSION in ravendb/http/request_executor.py (with .postN/.devN/rcN suffixes stripped from CLIENT_VERSION), then opens a PR labelled "release". - publish.yml: on merge of the labelled PR, builds sdist+wheel, uploads to PyPI via twine, then creates the version git tag + GitHub release. Requires repo secret PYPI_API_TOKEN and the "Allow GitHub Actions to create and approve pull requests" setting enabled.
1 parent 9ea3601 commit 0c67e1b

2 files changed

Lines changed: 132 additions & 0 deletions

File tree

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Prepare release PR
2+
3+
# Step 1 of the release flow.
4+
# Manually triggered. Bumps the version in setup.py and RequestExecutor.CLIENT_VERSION,
5+
# then opens a PR labelled `release`. Merging that PR fires `publish.yml`.
6+
7+
on:
8+
workflow_dispatch:
9+
inputs:
10+
version:
11+
description: "Release version, e.g. 7.2.3 (sets the ravendb package version)."
12+
required: true
13+
type: string
14+
15+
permissions:
16+
contents: write
17+
pull-requests: write
18+
19+
jobs:
20+
prepare:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- name: Bump version
26+
env:
27+
VERSION: ${{ inputs.version }}
28+
run: |
29+
set -euo pipefail
30+
# setup.py carries the full PEP 440 version, incl. any .postN/.devN/rcN suffix.
31+
sed -i -E "s/version=\"[0-9][^\"]*\"/version=\"${VERSION}\"/" setup.py
32+
33+
# RequestExecutor.CLIENT_VERSION is the server-facing client version and tracks
34+
# the clean release number only (a 7.2.1.post1 hotfix keeps CLIENT_VERSION 7.2.1).
35+
CLIENT_VERSION="$(printf '%s' "${VERSION}" | sed -E 's/(\.post[0-9]+|\.dev[0-9]+|(a|b|rc)[0-9]+).*$//')"
36+
sed -i -E "s/CLIENT_VERSION = \".*\"/CLIENT_VERSION = \"${CLIENT_VERSION}\"/" ravendb/http/request_executor.py
37+
38+
echo "----- setup.py -----"
39+
grep -nE 'version=' setup.py || true
40+
echo "----- request_executor.py -----"
41+
grep -nE 'CLIENT_VERSION = ' ravendb/http/request_executor.py || true
42+
43+
if git diff --quiet; then
44+
echo "::error::No version strings changed. Check the sed patterns."
45+
exit 1
46+
fi
47+
48+
- name: Create release PR
49+
uses: peter-evans/create-pull-request@v7
50+
with:
51+
token: ${{ secrets.GITHUB_TOKEN }}
52+
base: ${{ github.event.repository.default_branch }}
53+
branch: release/${{ inputs.version }}
54+
delete-branch: true
55+
commit-message: "Release ${{ inputs.version }}"
56+
title: "Release ${{ inputs.version }}"
57+
labels: release
58+
body: |
59+
Automated release for **ravendb ${{ inputs.version }}** (Python client).
60+
61+
Bumps `version` in `setup.py` and `RequestExecutor.CLIENT_VERSION`
62+
(`.postN`/`.devN`/`rcN` suffixes are stripped from `CLIENT_VERSION`).
63+
64+
> [!WARNING]
65+
> Merging this PR **while the `release` label is set** triggers the
66+
> **Publish to PyPI** workflow, which builds and uploads the package and
67+
> creates the `${{ inputs.version }}` GitHub release.
68+
69+
Review the diff, then merge to publish. Remove the `release` label before
70+
merging if you do **not** want to publish.

.github/workflows/publish.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Publish to PyPI
2+
3+
# Step 2 of the release flow.
4+
# Fires when a PR labelled `release` is merged (the PR opened by prepare-release.yml).
5+
# Also runnable manually as an emergency fallback (publishes whatever is on the branch).
6+
7+
on:
8+
pull_request:
9+
types: [closed]
10+
workflow_dispatch:
11+
12+
permissions:
13+
contents: write # create the git tag / GitHub release
14+
15+
jobs:
16+
publish:
17+
# Only on manual run, or on a merged PR that carried the `release` label.
18+
if: >-
19+
github.event_name == 'workflow_dispatch' ||
20+
(github.event.pull_request.merged == true &&
21+
contains(github.event.pull_request.labels.*.name, 'release'))
22+
runs-on: ubuntu-latest
23+
steps:
24+
- uses: actions/checkout@v4
25+
with:
26+
ref: ${{ github.event.pull_request.base.ref || github.ref_name }}
27+
28+
- uses: actions/setup-python@v5
29+
with:
30+
python-version: "3.11"
31+
32+
- name: Install build tooling
33+
run: python -m pip install --upgrade pip setuptools wheel twine
34+
35+
- name: Build sdist + wheel
36+
run: python setup.py sdist bdist_wheel
37+
38+
- name: Read package version
39+
id: ver
40+
run: echo "version=$(python setup.py --version)" >> "$GITHUB_OUTPUT"
41+
42+
- name: Publish to PyPI
43+
env:
44+
TWINE_USERNAME: __token__
45+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
46+
run: twine upload --non-interactive --skip-existing dist/*
47+
48+
- name: Tag & GitHub release
49+
env:
50+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51+
VERSION: ${{ steps.ver.outputs.version }}
52+
TARGET: ${{ github.event.pull_request.base.ref || github.ref_name }}
53+
run: |
54+
set -euo pipefail
55+
if gh release view "${VERSION}" >/dev/null 2>&1; then
56+
echo "Release ${VERSION} already exists, skipping."
57+
else
58+
gh release create "${VERSION}" \
59+
--target "${TARGET}" \
60+
--title "${VERSION}" \
61+
--notes "ravendb ${VERSION} published to PyPI."
62+
fi

0 commit comments

Comments
 (0)