Skip to content

Commit 0f592fd

Browse files
committed
Auto bump deploy
1 parent 523df21 commit 0f592fd

9 files changed

Lines changed: 189 additions & 134 deletions

File tree

.github/workflows/publish-python.yml

Lines changed: 98 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ on:
1111

1212
jobs:
1313
publish:
14+
if: ${{ github.actor != 'github-actions[bot]' }}
1415
runs-on: ubuntu-latest
1516
permissions:
16-
contents: read
17+
contents: write
1718
id-token: write
1819
defaults:
1920
run:
@@ -32,38 +33,126 @@ jobs:
3233
python -m pip install --upgrade pip
3334
python -m pip install build
3435
35-
- name: Decide whether to publish
36-
id: should_publish
36+
- name: Decide version
37+
id: version
3738
run: |
3839
python - <<'PY'
3940
import json
4041
import os
42+
import re
4143
import urllib.request
4244
import tomllib
4345
from pathlib import Path
4446
4547
data = tomllib.loads(Path("pyproject.toml").read_text())
4648
name = data["project"]["name"]
47-
version = data["project"]["version"]
49+
current = data["project"]["version"]
50+
51+
def parse(value: str) -> list[int]:
52+
core = value.split("-", 1)[0].split("+", 1)[0]
53+
parts = [int(part) for part in core.split(".") if part.isdigit()]
54+
while len(parts) < 3:
55+
parts.append(0)
56+
return parts[:3]
57+
58+
def compare(left: str, right: str) -> int:
59+
a = parse(left)
60+
b = parse(right)
61+
for i in range(3):
62+
if a[i] > b[i]:
63+
return 1
64+
if a[i] < b[i]:
65+
return -1
66+
return 0
67+
68+
def bump_patch(value: str) -> str:
69+
major, minor, patch = parse(value)
70+
return f"{major}.{minor}.{patch + 1}"
4871
4972
url = f"https://pypi.org/pypi/{name}/json"
5073
try:
5174
with urllib.request.urlopen(url, timeout=10) as resp:
5275
payload = json.loads(resp.read().decode("utf-8"))
53-
published = version in payload.get("releases", {})
76+
published = payload.get("info", {}).get("version")
5477
except Exception:
55-
published = False
78+
published = None
79+
80+
next_version = current
81+
bump_needed = False
82+
if published:
83+
comparison = compare(current, published)
84+
if comparison <= 0:
85+
next_version = bump_patch(current if comparison == 0 else published)
86+
bump_needed = True
87+
88+
publish = (published is None) or (compare(next_version, published) > 0 if published else True)
5689
5790
output = os.environ.get("GITHUB_OUTPUT")
5891
if output:
5992
with open(output, "a", encoding="utf-8") as handle:
60-
handle.write(f"publish={'false' if published else 'true'}\n")
93+
handle.write(f"current_version={current}\n")
94+
handle.write(f"published_version={published or ''}\n")
95+
handle.write(f"next_version={next_version}\n")
96+
handle.write(f"bump_needed={'true' if bump_needed else 'false'}\n")
97+
handle.write(f"publish={'true' if publish else 'false'}\n")
98+
PY
99+
100+
- name: Sync version files
101+
id: sync_version
102+
env:
103+
NEXT_VERSION: ${{ steps.version.outputs.next_version }}
104+
run: |
105+
python - <<'PY'
106+
import os
107+
import re
108+
from pathlib import Path
109+
110+
next_version = os.environ.get("NEXT_VERSION")
111+
if not next_version:
112+
raise SystemExit(0)
113+
114+
pyproject_path = Path("pyproject.toml")
115+
pyproject_text = pyproject_path.read_text()
116+
updated_pyproject = re.sub(
117+
r'(?m)^version = "[^"]+"',
118+
f'version = "{next_version}"',
119+
pyproject_text,
120+
count=1,
121+
)
122+
if updated_pyproject != pyproject_text:
123+
pyproject_path.write_text(updated_pyproject)
124+
125+
init_path = Path("src/diffio/__init__.py")
126+
if init_path.exists():
127+
init_text = init_path.read_text()
128+
updated_init = re.sub(
129+
r'(?m)^__version__ = "[^"]+"',
130+
f'__version__ = "{next_version}"',
131+
init_text,
132+
count=1,
133+
)
134+
if updated_init != init_text:
135+
init_path.write_text(updated_init)
61136
PY
137+
if git diff --quiet -- pyproject.toml src/diffio/__init__.py; then
138+
echo "changed=false" >> "$GITHUB_OUTPUT"
139+
else
140+
echo "changed=true" >> "$GITHUB_OUTPUT"
141+
fi
142+
143+
- name: Commit version update
144+
if: ${{ steps.sync_version.outputs.changed == 'true' }}
145+
run: |
146+
git config user.name "github-actions[bot]"
147+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
148+
git add pyproject.toml src/diffio/__init__.py
149+
git commit -m "chore(release): bump Python SDK to ${{ steps.version.outputs.next_version }}"
150+
git push origin "HEAD:${GITHUB_REF_NAME}"
62151
63152
- name: Build
64-
if: ${{ steps.should_publish.outputs.publish == 'true' }}
153+
if: ${{ steps.version.outputs.publish == 'true' }}
65154
run: python -m build
66155

67156
- name: Publish to PyPI
68-
if: ${{ steps.should_publish.outputs.publish == 'true' }}
157+
if: ${{ steps.version.outputs.publish == 'true' }}
69158
uses: pypa/gh-action-pypi-publish@release/v1

README.md

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,11 @@ pip install -e .
1818

1919
## Configuration
2020

21-
Set the API key with `DIFFIO_API_KEY`. You can also override the base URL with `DIFFIO_API_BASE_URL`.
21+
Set the API key with `DIFFIO_API_KEY`. If you need to set the base URL explicitly, use the production endpoint with `DIFFIO_API_BASE_URL`.
2222

2323
```bash
2424
export DIFFIO_API_KEY="diffio_live_..."
25-
export DIFFIO_API_BASE_URL="https://us-central1-diffioai.cloudfunctions.net"
26-
```
27-
28-
For emulators, set the base URL to the Functions emulator host.
29-
30-
```bash
31-
export DIFFIO_API_BASE_URL="http://127.0.0.1:5001/diffioai/us-central1"
25+
export DIFFIO_API_BASE_URL="https://us-central1-diffioai.cloudfunctions.net/v1"
3226
```
3327

3428
## Request options
@@ -167,16 +161,6 @@ for generation in generations.generations:
167161
print(generation.generationId, generation.status)
168162
```
169163

170-
## Webhooks portal access
171-
172-
```py
173-
from diffio import DiffioClient
174-
175-
client = DiffioClient(apiKey="diffio_live_...")
176-
portal = client.webhooks.get_portal_access(mode="test")
177-
print(portal.portalUrl)
178-
```
179-
180164
## Send a test webhook event
181165

182166
```py
@@ -185,13 +169,41 @@ from diffio import DiffioClient
185169
client = DiffioClient(apiKey="diffio_live_...")
186170
event = client.webhooks.send_test_event(
187171
eventType="generation.completed",
188-
mode="test",
172+
mode="live",
189173
samplePayload={"apiProjectId": "proj_123"},
190174
)
191175

192176
print(event.svixMessageId)
193177
```
194178

179+
## Verify webhook signatures
180+
181+
Use the raw request body (bytes) plus the `svix-*` headers and your webhook signing secret.
182+
183+
```py
184+
from fastapi import FastAPI, Request, HTTPException
185+
from diffio import DiffioClient
186+
import os
187+
188+
app = FastAPI()
189+
client = DiffioClient(apiKey=os.environ["DIFFIO_API_KEY"])
190+
191+
@app.post("/webhooks/diffio")
192+
async def diffio_webhook(request: Request):
193+
payload = await request.body()
194+
headers = request.headers
195+
try:
196+
event = client.webhooks.verify_signature(
197+
payload=payload,
198+
headers=headers,
199+
secret=os.environ["DIFFIO_WEBHOOK_SECRET"],
200+
)
201+
except Exception:
202+
raise HTTPException(status_code=400, detail="Invalid signature")
203+
print("Webhook received", event.eventType)
204+
return {"ok": True}
205+
```
206+
195207
## Tutorials
196208

197209
* Audio restoration CLI tutorial: `tutorials/audio-restoration-cli/README.md`

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ authors = [
1313
{ name = "Diffio" }
1414
]
1515
dependencies = [
16-
"httpx>=0.24.0"
16+
"httpx>=0.24.0",
17+
"svix>=1.84.1,<2.0.0"
1718
]
1819
classifiers = [
1920
"License :: OSI Approved :: MIT License",

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
httpx>=0.24.0
2+
svix>=1.84.1,<2.0.0

src/diffio/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
ProjectSummary,
2525
WebhookEventType,
2626
WebhookMode,
27-
WebhookPortalResponse,
2827
WebhookTestEventResponse,
2928
)
3029

@@ -51,7 +50,6 @@
5150
"RequestOptions",
5251
"WebhookEventType",
5352
"WebhookMode",
54-
"WebhookPortalResponse",
5553
"WebhookTestEventResponse",
5654
"WebhooksClient",
5755
]

0 commit comments

Comments
 (0)