Skip to content

Commit 9812f6e

Browse files
authored
Add release workflow (#92)
1 parent 7dc61ad commit 9812f6e

8 files changed

Lines changed: 131 additions & 24 deletions

File tree

.dev/test-version

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Release Instructions
2+
3+
Releases are driven by `v*` git tags. Pushing a tag triggers
4+
`.github/workflows/release.yml`, which runs the test suite, publishes the
5+
package to PyPI (`make publish`), then extracts the matching `## vX.Y.Z`
6+
section from `docs/release-notes.md` and publishes it as the GitHub Release
7+
body (re-runs update the existing release instead of failing).
8+
9+
## Cutting a release
10+
11+
1. Bump `version` in `pyproject.toml`. That is the single source of truth —
12+
`fluid.__version__` is read from the installed package metadata, so there
13+
is nothing else to edit.
14+
2. Add a `## vX.Y.Z` section at the top of `docs/release-notes.md` describing
15+
the changes. The release workflow fails if this section is missing.
16+
3. Commit and push to `main`; let the `build` workflow pass.
17+
4. Run `make release` — it reads the version from `pyproject.toml`, asks for
18+
confirmation, then creates and pushes the `vX.Y.Z` tag. The `release`
19+
workflow takes it from there.
20+
21+
Do not publish to PyPI manually; let the tagged workflow do it.

.github/workflows/build.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ jobs:
1313
timeout-minutes: 5
1414
env:
1515
PYTHON_ENV: ci
16-
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
1716
FLUID_FLAMEGRAPH_EXECUTABLE: "./flamegraph.pl"
1817
strategy:
1918
matrix:
@@ -50,8 +49,6 @@ jobs:
5049
run: ./.dev/install-flamegraph
5150
- name: run lint
5251
run: make lint-test
53-
- name: test version
54-
run: make test-version
5552
- name: build docs
5653
run: make docs
5754
- name: tests
@@ -62,9 +59,6 @@ jobs:
6259
with:
6360
token: ${{ secrets.CODECOV_TOKEN }}
6461
files: ./build/coverage.xml
65-
- name: publish
66-
if: ${{ github.ref == 'refs/heads/main' && matrix.python-version == '3.14' && github.event.head_commit.message == 'release' }}
67-
run: make publish
6862
- name: publish-docs
6963
if: ${{ github.ref == 'refs/heads/main' && matrix.python-version == '3.14' }}
7064
run: make docs-publish

.github/workflows/release.yml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: release
2+
3+
# Triggered by `v*` tags (push one with `make release`). Runs the test suite,
4+
# publishes the package to PyPI, then extracts the matching section from
5+
# docs/release-notes.md and publishes it as the GitHub Release body. Re-runs
6+
# idempotently update an existing release rather than failing.
7+
8+
on:
9+
push:
10+
tags:
11+
- "v*"
12+
13+
permissions:
14+
contents: write
15+
16+
jobs:
17+
release:
18+
runs-on: ubuntu-latest
19+
timeout-minutes: 10
20+
env:
21+
PYTHON_ENV: ci
22+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24+
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
25+
FLUID_FLAMEGRAPH_EXECUTABLE: "./flamegraph.pl"
26+
27+
services:
28+
postgres:
29+
image: postgres:15
30+
ports:
31+
- 5432:5432
32+
env:
33+
POSTGRES_USER: postgres
34+
POSTGRES_PASSWORD: postgres
35+
POSTGRES_DB: test_db
36+
37+
steps:
38+
- name: checkout code
39+
uses: actions/checkout@v4
40+
with:
41+
fetch-depth: 0
42+
- name: Set up Python
43+
uses: actions/setup-python@v5
44+
with:
45+
python-version: "3.14"
46+
- name: Start Redis
47+
uses: supercharge/redis-github-action@1.2.0
48+
with:
49+
redis-version: 7
50+
- name: Install dependencies
51+
run: make install
52+
- name: Install flamegraph
53+
env:
54+
FG_PATH: "."
55+
run: ./.dev/install-flamegraph
56+
- name: run lint
57+
run: make lint-test
58+
- name: build docs
59+
run: make docs
60+
- name: tests
61+
run: make test
62+
- name: publish to PyPI
63+
run: make publish
64+
- name: Extract release notes
65+
run: |
66+
TAG="${GITHUB_REF_NAME}"
67+
awk -v tag="## ${TAG}" '
68+
$0 == tag { in_section = 1; next }
69+
/^## / && in_section { exit }
70+
in_section { print }
71+
' docs/release-notes.md > /tmp/notes.md
72+
if [ ! -s /tmp/notes.md ]; then
73+
echo "No section '## ${TAG}' found in docs/release-notes.md" >&2
74+
exit 1
75+
fi
76+
echo "--- extracted notes for ${TAG} ---"
77+
cat /tmp/notes.md
78+
- name: Publish GitHub Release
79+
run: |
80+
TAG="${GITHUB_REF_NAME}"
81+
if gh release view "$TAG" >/dev/null 2>&1; then
82+
gh release edit "$TAG" --notes-file /tmp/notes.md
83+
else
84+
gh release create "$TAG" --title "$TAG" --notes-file /tmp/notes.md
85+
fi

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
@.github/instructions/makefile.instructions.md
44
@.github/instructions/code.instructions.md
55
@.github/instructions/tests.instructions.md
6+
@.github/instructions/release.instructions.md

Makefile

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,24 @@ outdated: ## Show outdated packages
4747
uv tree --outdated
4848

4949
.PHONY: publish
50-
publish: ## release to pypi and github tag
50+
publish: ## release to pypi
5151
@uv build && uv publish --token $(PYPI_TOKEN)
5252

5353
.PHONY: readme
5454
readme: ## generate readme.md
5555
cp docs/index.md readme.md
5656

57+
.PHONY: release
58+
release: ## tag current version (from pyproject.toml) and push
59+
$(eval VERSION := $(shell grep '^version' pyproject.toml | head -1 | sed 's/version = "\(.*\)"/\1/'))
60+
@read -p "Tagging with v$(VERSION), are you sure? [Y/n] " ans; \
61+
ans=$${ans:-Y}; \
62+
if [ "$$ans" = "Y" ] || [ "$$ans" = "y" ]; then \
63+
git tag -a v$(VERSION) -m "v$(VERSION)" && git push origin v$(VERSION); \
64+
else \
65+
echo "Aborted."; \
66+
fi
67+
5768
.PHONY: taplo-fmt
5869
taplo-fmt: ## format toml files with taplo
5970
taplo fmt
@@ -65,10 +76,6 @@ test: ## test with coverage
6576
-m "not flaky" \
6677
--cov --cov-report xml --cov-report html
6778

68-
.PHONY: test-version
69-
test-version: ## check version compatibility
70-
@./.dev/test-version
71-
7279
.PHONY: upgrade
7380
upgrade: ## upgrade all packages via uv
7481
uv lock --upgrade

docs/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<h1>
22
<a href="https://fluid.quantmind.com/">
33
<picture>
4-
<source media="(prefers-color-scheme: dark)" srcset="https://fluid.quantmind.com/assets/fluid-banner-dark.svg">
5-
<img alt="aio-fluid — async utilities for backend Python services" src="https://fluid.quantmind.com/assets/fluid-banner-light.svg" width="300">
4+
<source media="(prefers-color-scheme: dark)" srcset="https://fluid.quantmind.com/assets/fluid-banner-light.svg" style="max-width: 400px; width: 100%;">
5+
<img alt="aio-fluid — async utilities for backend Python services" src="https://fluid.quantmind.com/assets/fluid-banner-dark.svg" style="max-width: 400px; width: 100%;">
66
</picture>
77
</a>
88
</h1>

docs/release-notes.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Release Notes
2+
3+
## v2.2.4
4+
5+
Bug-fix release for the task scheduler.
6+
7+
- Fix task interruption handling. ([#89](https://github.com/quantmind/aio-fluid/pull/89))
8+
- Fix stale concurrent tasks not being released. ([#88](https://github.com/quantmind/aio-fluid/pull/88))
9+
- Fix task abort behaviour. ([#87](https://github.com/quantmind/aio-fluid/pull/87))
10+
- Patch `pydanclick` to work with `StrEnum`. ([#86](https://github.com/quantmind/aio-fluid/pull/86))

0 commit comments

Comments
 (0)