Skip to content

Commit 05ce285

Browse files
authored
Automate python publishing on version bumps (#72)
Automate the Python release pipeline so a `bonsai-py/Cargo.toml` version bump on main auto-tags + triggers publish. - Watches `bonsai-py/Cargo.toml`, pushes py-v$version on change. Uses a PAT (RELEASE_TAG_PAT) because GITHUB_TOKEN-pushed tags don't fire downstream workflows.
1 parent 73eb995 commit 05ce285

6 files changed

Lines changed: 92 additions & 12 deletions

File tree

.github/workflows/auto-tag-py.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Auto-tag Python release
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- 'bonsai-py/Cargo.toml'
8+
9+
permissions:
10+
contents: write
11+
12+
jobs:
13+
tag:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
token: ${{ secrets.RELEASE_TAG_PAT }}
19+
fetch-depth: 0 # need full history so `git rev-parse` can see existing tags
20+
21+
- name: Extract version from Cargo.toml
22+
id: version
23+
run: |
24+
version=$(grep -m1 '^version' bonsai-py/Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')
25+
if [ -z "$version" ]; then
26+
echo "::error::Could not parse version from bonsai-py/Cargo.toml"
27+
exit 1
28+
fi
29+
echo "version=$version" >> "$GITHUB_OUTPUT"
30+
echo "Detected version: $version"
31+
32+
- name: Check if py-v tag already exists
33+
id: check
34+
run: |
35+
v="${{ steps.version.outputs.version }}"
36+
if git rev-parse "py-v$v" >/dev/null 2>&1; then
37+
echo "py-v$v already exists — no-op."
38+
echo "skip=true" >> "$GITHUB_OUTPUT"
39+
else
40+
echo "py-v$v does not exist — will tag."
41+
echo "skip=false" >> "$GITHUB_OUTPUT"
42+
fi
43+
44+
- name: Configure git
45+
if: steps.check.outputs.skip == 'false'
46+
run: |
47+
git config user.name "github-actions[bot]"
48+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
49+
50+
- name: Push py-v-X.Y.Z (real PyPI release)
51+
if: steps.check.outputs.skip == 'false'
52+
run: |
53+
v="${{ steps.version.outputs.version }}"
54+
git tag "py-v$v"
55+
git push origin "py-v$v"

.github/workflows/python-wheels.yml

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Python wheels
33
on:
44
push:
55
branches: [main]
6-
tags: ["py-v*", "py-test-*"]
6+
tags: ["py-v*"]
77
pull_request:
88
branches: [main]
99
workflow_dispatch: # manual ad-hoc builds from any branch
@@ -63,7 +63,6 @@ jobs:
6363
run: |
6464
tag="${GITHUB_REF#refs/tags/}"
6565
version="${tag#py-v}"
66-
version="${version#py-test-}"
6766
cargo_version=$(grep -m1 '^version' bonsai-py/Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')
6867
if [ "$version" != "$cargo_version" ]; then
6968
echo "::error::Tag version '$version' does not match Cargo.toml version '$cargo_version'."
@@ -149,12 +148,12 @@ jobs:
149148
python -c "import bonsai_bt; print(bonsai_bt.__version__)"
150149
151150
publish:
152-
name: Publish to PyPI / TestPyPI
151+
name: Publish to PyPI
153152
needs: [build, sdist, verify-sdist]
154-
if: startsWith(github.ref, 'refs/tags/py-v') || startsWith(github.ref, 'refs/tags/py-test-')
153+
if: startsWith(github.ref, 'refs/tags/py-v')
155154
runs-on: ubuntu-latest
156155
environment:
157-
name: ${{ startsWith(github.ref, 'refs/tags/py-test-') && 'testpypi' || 'pypi' }}
156+
name: pypi
158157
permissions:
159158
id-token: write # OIDC for Trusted Publishing
160159
steps:
@@ -174,7 +173,5 @@ jobs:
174173

175174
- uses: pypa/gh-action-pypi-publish@release/v1
176175
with:
177-
repository-url: >-
178-
${{ startsWith(github.ref, 'refs/tags/py-test-') && 'https://test.pypi.org/legacy/' || 'https://upload.pypi.org/legacy/' }}
179176
packages-dir: dist
180177
skip-existing: true

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<!-- [![version](https://img.shields.io/badge/version-1.0.0-blue)](https://GitHub.com/Sollimann/CleanIt/releases/) -->
1111
[![Build Status](https://github.com/Sollimann/bonsai/actions/workflows/rust-ci.yml/badge.svg)](https://github.com/Sollimann/bonsai/actions)
1212
[![Bonsai crate](https://img.shields.io/crates/v/bonsai-bt.svg)](https://crates.io/crates/bonsai-bt)
13+
[![PyPI](https://img.shields.io/pypi/v/bonsai-bt.svg?label=pypi%20%28bonsai-bt%29)](https://pypi.org/project/bonsai-bt/)
1314
[![minimum rustc 1.72](https://img.shields.io/badge/rustc-1.72+-blue.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
1415
[![Docs](https://docs.rs/bonsai-bt/badge.svg)](https://docs.rs/bonsai-bt)
1516
[![codecov](https://codecov.io/gh/Sollimann/bonsai/branch/main/graph/badge.svg?token=JX8JBPWORV)](https://codecov.io/gh/Sollimann/bonsai)
@@ -41,7 +42,13 @@ bonsai-bt = "*"
4142

4243
### Python
4344

44-
Python bindings are available — see [`bonsai-py/`](bonsai-py/) for installation, examples, and a side-by-side comparison of the same BT in Rust and Python. The package wraps the same Rust crate, so the BT semantics are identical; only the API surface differs.
45+
Bonsai is available on PyPI as [**`bonsai-bt`**](https://pypi.org/project/bonsai-bt/):
46+
47+
```bash
48+
pip install bonsai-bt
49+
```
50+
51+
See [`bonsai-py/`](bonsai-py/) for examples.
4552

4653
## What is a Behavior Tree?
4754

bonsai-py/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bonsai-py"
3-
version = "0.12.0"
3+
version = "0.12.1"
44
edition = "2021"
55
rust-version = "1.80.0"
66
description = "Python bindings for the bonsai-bt behavior tree library"

bonsai-py/README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,31 @@
1-
# bonsai-bt - Python bindings
1+
2+
<p align="center">
3+
<img src="https://raw.githubusercontent.com/Sollimann/bonsai/main/docs/resources/gifs/bonsai.gif" width="350" alt="Bonsai logo">
4+
</p>
5+
6+
[![PyPI](https://img.shields.io/pypi/v/bonsai-bt.svg)](https://pypi.org/project/bonsai-bt/)
7+
[![Python](https://img.shields.io/pypi/pyversions/bonsai-bt.svg)](https://pypi.org/project/bonsai-bt/)
8+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
29

310
Python bindings for the [bonsai-bt](https://github.com/sollimann/bonsai)
411
behavior-tree library.
512

13+
## Install
14+
15+
```bash
16+
pip install bonsai-bt
17+
```
18+
19+
The package is published on PyPI as [**`bonsai-bt`**](https://pypi.org/project/bonsai-bt/) and imported as `bonsai_bt`:
20+
21+
```python
22+
import bonsai_bt as bt
23+
```
24+
625
## Installation (dev)
726

27+
For building from source — needed if you're contributing to the Rust core or developing against an unpublished version:
28+
829
```bash
930
python -m venv .venv
1031
source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1

bonsai-py/tests/test_module.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66

77
def test_version_present() -> None:
8-
"""bt.__version__ pins the wheel version (0.12.0); bump per release."""
9-
assert bt.__version__ == "0.12.0"
8+
"""bt.__version__ pins the wheel version (0.12.1); bump per release."""
9+
assert bt.__version__ == "0.12.1"
1010

1111

1212
def test_docstring_present() -> None:

0 commit comments

Comments
 (0)